├── m4 └── .gitignore ├── ac └── .gitignore ├── .gitmodules ├── meson_options.txt ├── compiler ├── c.capnp.c ├── c++.capnp.c ├── c++.capnp.h ├── c.capnp.h ├── update-notes.md ├── c++.capnp ├── str.h ├── c.capnp ├── str.c ├── schema.capnp ├── schema-test.cpp ├── test.capnp └── schema.capnp.h ├── c-capnproto.pc.in ├── .travis.yml ├── .gitignore ├── subprojects └── gtest.wrap ├── COPYING ├── .github └── workflows │ └── ci.yml ├── configure.ac ├── lib ├── capnp_priv.h ├── capn-list.inc ├── capn-stream.c ├── capn-malloc.c ├── capnp_c.h └── capn.c ├── tests ├── addressbook.capnp ├── addressbook.capnp.h ├── example-test.cpp ├── addressbook.capnp.c ├── capn-stream-test.cpp └── capn-test.cpp ├── meson.build ├── Makefile.am └── README.md /m4/.gitignore: -------------------------------------------------------------------------------- 1 | *.m4 2 | -------------------------------------------------------------------------------- /ac/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gtest"] 2 | path = gtest 3 | url = https://github.com/google/googletest.git 4 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('enable_tests', type: 'boolean', value: true, description: 'Build unit tests in test/ and compiler/') 2 | -------------------------------------------------------------------------------- /compiler/c.capnp.c: -------------------------------------------------------------------------------- 1 | #include "c.capnp.h" 2 | /* AUTO GENERATED - DO NOT EDIT */ 3 | #ifdef __GNUC__ 4 | # define capnp_unused __attribute__((unused)) 5 | # define capnp_use(x) (void) x; 6 | #else 7 | # define capnp_unused 8 | # define capnp_use(x) 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /compiler/c++.capnp.c: -------------------------------------------------------------------------------- 1 | #include "c++.capnp.h" 2 | /* AUTO GENERATED - DO NOT EDIT */ 3 | #ifdef __GNUC__ 4 | # define capnp_unused __attribute__((unused)) 5 | # define capnp_use(x) (void) x; 6 | #else 7 | # define capnp_unused 8 | # define capnp_use(x) 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /c-capnproto.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | bindir=@bindir@ 5 | includedir=@includedir@ 6 | codegen=${bindir}/capnpc-c 7 | 8 | Name: c-capnproto 9 | Description: Cap'n Proto C bindings 10 | Version: @PACKAGE_VERSION@ 11 | Libs: -L${libdir} -lcapnp_c 12 | Cflags: -I${includedir} 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | # need at least gcc 4.8 for -std=c++11 4 | addons: 5 | apt: 6 | sources: 7 | - ubuntu-toolchain-r-test 8 | packages: 9 | - gcc-4.8 10 | - g++-4.8 11 | 12 | # use gcc-4.8 13 | install: 14 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi 15 | 16 | script: autoreconf -f -i -s && ./configure --without-gtest && make && make check 17 | 18 | compiler: 19 | - clang 20 | - gcc 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | aclocal.m4 2 | autom4te*.cache 3 | configure 4 | config.h* 5 | confdefs.h 6 | config.status 7 | libtool 8 | stamp-h* 9 | 10 | Makefile 11 | Makefile.in 12 | .deps 13 | .libs 14 | .dirstamp 15 | 16 | test-driver 17 | *.log 18 | *.trs 19 | 20 | tests/*.out 21 | 22 | *.o 23 | *.a 24 | *.so 25 | *.lo 26 | *.la 27 | 28 | capn-test 29 | capnpc-c 30 | c-capnproto.pc 31 | 32 | *.tar.gz 33 | 34 | subprojects/googletest-* 35 | subprojects/packagecache 36 | -------------------------------------------------------------------------------- /compiler/c++.capnp.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPN_BDF87D7BB8304E81 2 | #define CAPN_BDF87D7BB8304E81 3 | /* AUTO GENERATED - DO NOT EDIT */ 4 | #include 5 | 6 | #if CAPN_VERSION != 1 7 | #error "version mismatch between capnp_c.h and generated code" 8 | #endif 9 | 10 | #ifndef capnp_nowarn 11 | # ifdef __GNUC__ 12 | # define capnp_nowarn __extension__ 13 | # else 14 | # define capnp_nowarn 15 | # endif 16 | #endif 17 | 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | #endif 36 | -------------------------------------------------------------------------------- /compiler/c.capnp.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPN_C0183DD65FFEF0F3 2 | #define CAPN_C0183DD65FFEF0F3 3 | /* AUTO GENERATED - DO NOT EDIT */ 4 | #include 5 | 6 | #if CAPN_VERSION != 1 7 | #error "version mismatch between capnp_c.h and generated code" 8 | #endif 9 | 10 | #ifndef capnp_nowarn 11 | # ifdef __GNUC__ 12 | # define capnp_nowarn __extension__ 13 | # else 14 | # define capnp_nowarn 15 | # endif 16 | #endif 17 | 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | #endif 36 | -------------------------------------------------------------------------------- /subprojects/gtest.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = googletest-1.13.0 3 | source_url = https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz 4 | source_filename = gtest-1.13.0.tar.gz 5 | source_hash = ad7fdba11ea011c1d925b3289cf4af2c66a352e18d4c7264392fead75e919363 6 | patch_filename = gtest_1.13.0-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.13.0-1/get_patch 8 | patch_hash = 6d82a02c3a45071cea989983bf6becde801cbbfd29196ba30dada0215393b082 9 | wrapdb_version = 1.13.0-1 10 | 11 | [provide] 12 | gtest = gtest_dep 13 | gtest_main = gtest_main_dep 14 | gmock = gmock_dep 15 | gmock_main = gmock_main_dep 16 | -------------------------------------------------------------------------------- /compiler/update-notes.md: -------------------------------------------------------------------------------- 1 | 2 | occasionally, it may be required to sync with upstream capn proto changes. some quick notes on the process i've used here, assuming the updated capnproto repo is at CAPNP_CPP: 3 | 4 | $ cp ${CAPNP_CPP}/c++/src/capnp/test.capnp . 5 | $ cp ${CAPNP_CPP}/c++/src/capnp/schema.capnp . 6 | $ cp ${CAPNP_CPP}/c++/src/capnp/c++.capnp . 7 | 8 | fix up `schema.capnp` to reference the in-tree copy of `c++.capnp` (ie, `using Cxx = import "c++.capnp";` at the top of the file) 9 | 10 | then, regenerate the schema support: 11 | 12 | $ capnp compile -o ./capnpc-c compiler/schema.capnp 13 | 14 | now try to regenerate again, based on the previously regenerated schema. 15 | 16 | you can always check the capnpc formatted output during debugging: 17 | 18 | $ capnp compile -ocapnpc-capnpc compiler/schema.capnp 19 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 James McKaskill 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI Unit Tests" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | Normal: 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v3 15 | - name: Install meson and ninja 16 | run: pip3 install --user meson ninja 17 | - name: Run Unit Tests 18 | run: | 19 | export PATH=${HOME}/.local/bin:${PATH} 20 | meson setup -Dbuildtype=release build 21 | meson compile -C build 22 | build/capn-test 23 | 24 | Sanitizers: 25 | runs-on: ubuntu-22.04 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v3 29 | - name: Install meson and ninja 30 | run: pip3 install --user meson ninja 31 | - name: Run Unit Tests with ASAN 32 | env: 33 | ASAN_OPTIONS: detect_leaks=0,detect_odr_violation=0,allocator_may_return_null=1 34 | run: | 35 | export PATH=${HOME}/.local/bin:${PATH} 36 | meson setup -Dbuildtype=debugoptimized -Db_sanitize=address,undefined build 37 | meson compile -C build 38 | build/capn-test 39 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.60) 2 | 3 | AC_INIT(c-capnproto, 0.3, []) 4 | AC_CONFIG_SRCDIR(lib/capnp_c.h) 5 | AC_CONFIG_MACRO_DIR([m4]) 6 | AC_CONFIG_AUX_DIR([ac]) 7 | 8 | AC_CANONICAL_BUILD() 9 | AC_CANONICAL_HOST() 10 | AC_CANONICAL_TARGET() 11 | 12 | AM_INIT_AUTOMAKE(1.11) 13 | AM_SILENT_RULES([yes]) 14 | AC_CONFIG_HEADERS([config.h]) 15 | 16 | AC_USE_SYSTEM_EXTENSIONS 17 | 18 | LT_INIT 19 | 20 | AC_LANG([C]) 21 | AC_PROG_CC 22 | AC_PROG_CXX 23 | 24 | AC_PROG_INSTALL 25 | AC_PROG_LN_S 26 | 27 | AC_ARG_ENABLE(werror, 28 | AS_HELP_STRING([--enable-werror], [enable -Werror (for developers only)])) 29 | if test x"${enable_werror}" = x"yes" ; then 30 | WERROR="-Werror" 31 | fi 32 | AC_SUBST(WERROR) 33 | 34 | AC_ARG_WITH(capnpdir, 35 | AS_HELP_STRING([--with-capnpdir=DIR], [directory to install c.capnp file in (default: $includedir/capnp)])) 36 | if test x"${with_capnpdir}" != x ; then 37 | capnpdir="${with_capnpdir}" 38 | else 39 | capnpdir="${includedir}/capnp" 40 | fi 41 | AC_SUBST(capnpdir) 42 | 43 | #PKG_CHECK_MODULES(CAPNP, [capnp >= 0.5.2], [], [ 44 | # AC_MSG_ERROR([capnproto base package (0.5.2 or newer) not found]) 45 | #]) 46 | 47 | AC_CONFIG_SUBDIRS([gtest/googletest]) 48 | 49 | AC_CONFIG_FILES([ 50 | Makefile 51 | c-capnproto.pc 52 | ]) 53 | AC_OUTPUT 54 | -------------------------------------------------------------------------------- /compiler/c++.capnp: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 | # Licensed under the MIT License: 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | @0xbdf87d7bb8304e81; 23 | $namespace("capnp::annotations"); 24 | 25 | annotation namespace(file): Text; 26 | annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; 27 | -------------------------------------------------------------------------------- /compiler/str.h: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* str.h 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * 6 | * This software may be modified and distributed under the terms 7 | * of the MIT license. See the LICENSE file for details. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | struct str { 15 | char *str; 16 | int len, cap; 17 | }; 18 | 19 | extern char str_static[]; 20 | #define STR_INIT {str_static, 0, 0} 21 | 22 | void str_reserve(struct str *v, int sz); 23 | 24 | static inline void str_init(struct str *v, int sz) { 25 | v->str = str_static; 26 | v->len = v->cap = 0; 27 | if (sz) 28 | str_reserve(v, sz); 29 | } 30 | 31 | static inline void str_release(struct str *v) { 32 | if (v->cap) { 33 | free(v->str); 34 | } 35 | } 36 | 37 | static inline void str_reset(struct str *v) { 38 | if (v->len) { 39 | v->len = 0; 40 | v->str[0] = '\0'; 41 | } 42 | } 43 | 44 | static inline void str_setlen(struct str *v, int sz) { 45 | str_reserve(v, sz); 46 | v->str[sz] = '\0'; 47 | v->len = sz; 48 | } 49 | 50 | #ifdef __GNUC__ 51 | #define ATTR(FMT, ARGS) __attribute__((format(printf,FMT,ARGS))) 52 | #else 53 | #define ATTR(FMT, ARGS) 54 | #endif 55 | 56 | void str_add(struct str *v, const char *str, int sz); 57 | int str_vaddf(struct str *v, const char *format, va_list ap) ATTR(2,0); 58 | int str_addf(struct str *v, const char *format, ...) ATTR(2,3); 59 | char *strf(struct str *v, const char *format, ...) ATTR(2,3); 60 | 61 | 62 | -------------------------------------------------------------------------------- /lib/capnp_priv.h: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* capnp_c.h 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * Copyright (C) 2014 Steve Dee 6 | * 7 | * This software may be modified and distributed under the terms 8 | * of the MIT license. See the LICENSE file for details. 9 | */ 10 | 11 | /* 12 | * functions / structures in this header are private to the capnproto-c 13 | * library; applications should not call or use them. 14 | */ 15 | 16 | #ifndef CAPNP_PRIV_H 17 | #define CAPNP_PRIV_H 18 | 19 | #include "capnp_c.h" 20 | 21 | #if defined(__GNUC__) && __GNUC__ >= 4 22 | # define intern __attribute__((visibility ("internal"))) 23 | #else 24 | # define intern /**/ 25 | #endif 26 | 27 | /* capn_stream encapsulates the needed fields for capn_(deflate|inflate) in a 28 | * similar manner to z_stream from zlib 29 | * 30 | * The user should set next_in, avail_in, next_out, avail_out to the 31 | * available in/out buffers before calling capn_(deflate|inflate). 32 | * 33 | * Other fields should be zero initialized. 34 | */ 35 | struct capn_stream { 36 | const uint8_t *next_in; 37 | size_t avail_in; 38 | uint8_t *next_out; 39 | size_t avail_out; 40 | unsigned zeros, raw; 41 | 42 | uint8_t inflate_buf[8]; 43 | size_t avail_buf; 44 | }; 45 | 46 | #define CAPN_MISALIGNED -1 47 | #define CAPN_NEED_MORE -2 48 | 49 | /* capn_deflate deflates a stream to the packed format 50 | * capn_inflate inflates a stream from the packed format 51 | * 52 | * Returns: 53 | * CAPN_MISALIGNED - if the unpacked data is not 8 byte aligned 54 | * CAPN_NEED_MORE - more packed data/room is required (out for inflate, in for 55 | * deflate) 56 | * 0 - success, all output for inflate, all input for deflate processed 57 | */ 58 | intern int capn_deflate(struct capn_stream*); 59 | intern int capn_inflate(struct capn_stream*); 60 | 61 | 62 | #endif /* CAPNP_PRIV_H */ 63 | -------------------------------------------------------------------------------- /tests/addressbook.capnp: -------------------------------------------------------------------------------- 1 | # Based on the addressbook.capnp example in the capnproto C++ project: 2 | # https://github.com/sandstorm-io/capnproto/blob/6816634a08b08bc8f52b4ee809afb58389f19655/c%2B%2B/samples/addressbook.capnp 3 | # 4 | # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 5 | # Licensed under the MIT License: 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | # THE SOFTWARE. 24 | 25 | @0x9eb32e19f86ee174; 26 | 27 | using C = import "/c.capnp"; 28 | $C.fieldgetset; 29 | 30 | struct Person { 31 | id @0 :UInt32; 32 | name @1 :Text; 33 | email @2 :Text; 34 | phones @3 :List(PhoneNumber); 35 | 36 | struct PhoneNumber { 37 | number @0 :Text; 38 | type @1 :Type; 39 | 40 | enum Type { 41 | mobile @0; 42 | home @1; 43 | work @2; 44 | } 45 | } 46 | 47 | employment :union { 48 | unemployed @4 :Void; 49 | employer @5 :Text; 50 | school @6 :Text; 51 | selfEmployed @7 :Void; 52 | # We assume that a person is only one of these. 53 | } 54 | } 55 | 56 | struct AddressBook { 57 | people @0 :List(Person); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('capnp-c', ['c','cpp'], meson_version: '>=1.0.0', default_options : ['c_std=c99', 'cpp_std=c++14']) 2 | 3 | cc = meson.get_compiler('c') 4 | 5 | common_c_args = [] 6 | common_cpp_args = ['-std=c++14'] 7 | libcapnp_c_args = [] 8 | libcapnp_src = [ 9 | 'lib' / 'capn-malloc.c', 10 | 'lib' / 'capn-stream.c', 11 | 'lib' / 'capn.c', 12 | ] 13 | 14 | libcapnp = library('capnp', libcapnp_src, 15 | c_args : common_c_args + libcapnp_c_args, 16 | dependencies: [], 17 | implicit_include_directories: false, 18 | include_directories: include_directories(['compiler', 'lib']) 19 | ) 20 | 21 | libcapnp_dep = declare_dependency( 22 | link_with: libcapnp, 23 | dependencies: [], 24 | include_directories: include_directories(['compiler', 'lib']) 25 | ) 26 | 27 | capnpc_src = [ 28 | 'compiler' / 'capnpc-c.c', 29 | 'compiler' / 'schema.capnp.c', 30 | 'compiler' / 'str.c' 31 | ] 32 | 33 | capnpc_c = executable('capnpc-c', capnpc_src, 34 | include_directories: include_directories(['lib']), 35 | dependencies: [libcapnp_dep], 36 | c_args : common_c_args, 37 | ) 38 | 39 | capn_test_src = [ 40 | 'tests' / 'capn-test.cpp', 41 | 'tests' / 'capn-stream-test.cpp', 42 | 'tests' / 'example-test.cpp', 43 | 'tests' / 'addressbook.capnp.c', 44 | 'compiler' / 'test.capnp.c', 45 | 'compiler' / 'schema-test.cpp', 46 | 'compiler' / 'schema.capnp.c' 47 | ] 48 | 49 | if get_option('enable_tests') and not meson.is_subproject() 50 | 51 | thread_dep = dependency('threads') 52 | 53 | gtest_proj = subproject('gtest') 54 | gtest_dep = gtest_proj.get_variable('gtest_dep') 55 | gmock_dep = gtest_proj.get_variable('gmock_dep') 56 | 57 | test_dependencies = [libcapnp_dep, gtest_dep, gmock_dep, thread_dep] 58 | 59 | if get_option('b_sanitize').contains('address') 60 | test_dependencies += cc.find_library('asan') 61 | endif 62 | if get_option('b_sanitize').contains('undefined') 63 | test_dependencies += cc.find_library('ubsan') 64 | endif 65 | 66 | exe = executable('capn-test', capn_test_src, 67 | include_directories: include_directories(['lib', 'tests', 'compiler']), 68 | dependencies: test_dependencies, 69 | c_args : common_c_args, 70 | cpp_args : common_cpp_args, 71 | install: false, 72 | install_rpath: '', 73 | implicit_include_directories: false 74 | ) 75 | test('capn-test', exe) 76 | 77 | endif 78 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | AUTOMAKE_OPTIONS = foreign subdir-objects 3 | 4 | lib_LTLIBRARIES = 5 | bin_PROGRAMS = 6 | check_PROGRAMS = 7 | EXTRA_DIST = 8 | noinst_HEADERS = 9 | include_HEADERS = 10 | 11 | 12 | EXTRA_DIST += README.md 13 | 14 | EXTRA_DIST += c-capnproto.pc.in 15 | pkgconfigdir = $(libdir)/pkgconfig 16 | pkgconfig_DATA = c-capnproto.pc 17 | 18 | EXTRA_DIST += compiler/c.capnp 19 | capnp_DATA = compiler/c.capnp 20 | AM_CPPFLAGS = \ 21 | -I${srcdir}/compiler \ 22 | -I${srcdir}/lib 23 | 24 | lib_LTLIBRARIES += libcapnp_c.la 25 | libcapnp_c_la_LDFLAGS = -version-info 0:0:0 26 | libcapnp_c_la_SOURCES = \ 27 | lib/capn-malloc.c \ 28 | lib/capn-stream.c \ 29 | lib/capn.c 30 | EXTRA_DIST += \ 31 | lib/capn-list.inc 32 | 33 | bin_PROGRAMS += capnpc-c 34 | capnpc_c_SOURCES = \ 35 | compiler/capnpc-c.c \ 36 | compiler/schema.capnp.c \ 37 | compiler/str.c 38 | capnpc_c_LDADD = libcapnp_c.la 39 | include_HEADERS += \ 40 | lib/capnp_c.h 41 | 42 | noinst_HEADERS += \ 43 | lib/capnp_priv.h \ 44 | compiler/str.h \ 45 | compiler/schema.capnp.h \ 46 | compiler/c.capnp.h \ 47 | compiler/c++.capnp.h 48 | 49 | # Don't try to generate any *.capnp files. Otherwise make wants to compile them 50 | # from *.capnp.c and fails. 51 | %.capnp: ; 52 | 53 | # googletest 54 | GTEST_LDADD = gtest/googletest/lib/libgtest.la 55 | gtest/googletest/lib/libgtest.la: 56 | make -C gtest/googletest lib/libgtest.la 57 | GTEST_CPPFLAGS = -I${srcdir}/gtest/googletest/include 58 | DIST_SUBDIRS = gtest/googletest 59 | 60 | # Tests 61 | check_PROGRAMS += \ 62 | capn-test 63 | capn_test_SOURCES = \ 64 | tests/capn-test.cpp \ 65 | tests/capn-stream-test.cpp \ 66 | tests/example-test.cpp \ 67 | tests/addressbook.capnp.c \ 68 | compiler/test.capnp.c \ 69 | compiler/schema-test.cpp \ 70 | compiler/schema.capnp.c 71 | noinst_HEADERS += \ 72 | compiler/test.capnp.h \ 73 | tests/addressbook.capnp.h 74 | EXTRA_DIST += \ 75 | compiler/c.capnp \ 76 | compiler/c++.capnp \ 77 | compiler/schema.capnp \ 78 | compiler/test.capnp \ 79 | tests/addressbook.capnp 80 | capn_test_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_CPPFLAGS) 81 | capn_test_CXXFLAGS = -std=gnu++11 -pthread 82 | capn_test_LDADD = libcapnp_c.la $(GTEST_LDADD) 83 | capn_test_LDFLAGS = -pthread 84 | TESTS = capn-test 85 | 86 | CAPNP_SCHEMA_FILES := $(shell find . -type f -name \*.capnp) 87 | 88 | CAPNP ?= capnp 89 | .PHONY: capnp-compile 90 | capnp-compile: 91 | $(CAPNP) compile \ 92 | --output=./capnpc-c \ 93 | -Icompiler \ 94 | $(CAPNP_SCHEMA_FILES) 95 | -------------------------------------------------------------------------------- /compiler/c.capnp: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 NetDEF, Inc. and contributors 2 | # Licensed under the MIT License: 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | @0xc0183dd65ffef0f3; 23 | 24 | annotation nameinfix @0x85a8d86d736ba637 (file): Text; 25 | # add an infix (middle insert) for output file names 26 | # 27 | # "make" generally has implicit rules for compiling "foo.c" => "foo". This 28 | # is very annoying with capnp since the rule will be "foo" => "foo.c", leading 29 | # to a loop. $nameinfix (recommended parameter: "-gen") inserts its parameter 30 | # before the ".c", so the filename becomes "foo-gen.c" 31 | # 32 | # Alternatively, add this Makefile rule to disable compiling "foo.capnp.c" -> "foo.capnp": 33 | # %.capnp: ; 34 | # 35 | # 36 | # ("foo" is really "foo.capnp", so it's foo.capnp-gen.c) 37 | 38 | annotation fieldgetset @0xf72bc690355d66de (file): Void; 39 | # generate getter & setter functions for accessing fields 40 | # 41 | # allows grabbing/putting values without de-/encoding the entire struct. 42 | 43 | annotation donotinclude @0x8c99797357b357e9 (file): UInt64; 44 | # do not generate an include directive for an import statement for the file with 45 | # the given ID 46 | 47 | annotation typedefto @0xcefaf27713042144 (struct, enum): Text; 48 | # generate a typedef for the annotated struct or enum declaration 49 | 50 | annotation namespace @0xf2c035025fec7c2b (file): Text; 51 | # prefix structs with a name space string 52 | -------------------------------------------------------------------------------- /compiler/str.c: -------------------------------------------------------------------------------- 1 | /* str.c 2 | * 3 | * Copyright (C) 2013 James McKaskill 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include "str.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #ifndef va_copy 15 | # ifdef _MSC_VER 16 | # define va_copy(d,s) d = s 17 | # elif defined __GNUC__ 18 | # define va_copy(d,s) __builtin_va_copy(d,s) 19 | # else 20 | # error 21 | # endif 22 | #endif 23 | 24 | char str_static[] = "\0"; 25 | 26 | void str_reserve(struct str *v, int sz) { 27 | if (sz < v->cap) 28 | return; 29 | 30 | v->cap = (v->cap * 2) + 16; 31 | if (sz > v->cap) { 32 | v->cap = (sz + 8) & ~7; 33 | } 34 | 35 | if (v->str == str_static) { 36 | v->str = NULL; 37 | } 38 | 39 | v->str = realloc(v->str, v->cap + 1); 40 | } 41 | 42 | void str_add(struct str *v, const char *str, int sz) { 43 | if (sz < 0) 44 | sz = strlen(str); 45 | str_reserve(v, v->len + sz); 46 | memcpy(v->str+v->len, str, sz); 47 | v->len += sz; 48 | v->str[v->len] = '\0'; 49 | } 50 | 51 | int str_vaddf(struct str *v, const char* format, va_list ap) { 52 | str_reserve(v, v->len + 1); 53 | 54 | for (;;) { 55 | int ret; 56 | 57 | char* buf = v->str + v->len; 58 | int bufsz = v->cap - v->len; 59 | 60 | va_list aq; 61 | va_copy(aq, ap); 62 | 63 | /* We initialise buf[bufsz] to \0 to detect when snprintf runs out of 64 | * buffer by seeing whether it overwrites it. 65 | */ 66 | buf[bufsz] = '\0'; 67 | ret = vsnprintf(buf, bufsz + 1, format, aq); 68 | 69 | if (ret > bufsz) { 70 | /* snprintf has told us the size of buffer required (ISO C99 71 | * behavior) 72 | */ 73 | str_reserve(v, v->len + ret); 74 | 75 | } else if (ret >= 0) { 76 | /* success */ 77 | v->len += ret; 78 | return ret; 79 | 80 | } else if (buf[bufsz] != '\0') { 81 | /* snprintf has returned an error but has written to the end of the 82 | * buffer (MSVC behavior). The buffer is not large enough so grow 83 | * and retry. This can also occur with a format error if it occurs 84 | * right on the boundary, but then we grow the buffer and can 85 | * figure out its an error next time around. 86 | */ 87 | str_reserve(v, v->len + bufsz + 1); 88 | 89 | } else { 90 | /* snprintf has returned an error but has not written to the last 91 | * character in the buffer. We have a format error. 92 | */ 93 | return -1; 94 | } 95 | } 96 | } 97 | 98 | 99 | int str_addf(struct str *v, const char* format, ...) { 100 | va_list ap; 101 | va_start(ap, format); 102 | return str_vaddf(v, format, ap); 103 | } 104 | 105 | char *strf(struct str *v, const char* format, ...) { 106 | va_list ap; 107 | va_start(ap, format); 108 | str_reset(v); 109 | str_vaddf(v, format, ap); 110 | return v->str; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /lib/capn-list.inc: -------------------------------------------------------------------------------- 1 | /* capn-list.inc 2 | * 3 | * Copyright (C) 2013 James McKaskill 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #define CAT2(A,B) A ## B 10 | #define CAT(A,B) CAT2(A, B) 11 | #define UINT_T CAT(CAT(uint, SZ), _t) 12 | #define LIST_T CAT(capn_list, SZ) 13 | #define FLIP CAT(capn_flip, SZ) 14 | 15 | UINT_T CAT(capn_get,SZ) (LIST_T l, int off) { 16 | char *d; 17 | capn_ptr p = l.p; 18 | if (off >= p.len) { 19 | return 0; 20 | } 21 | 22 | switch (p.type) { 23 | case CAPN_LIST: 24 | if (p.datasz < SZ/8) 25 | return 0; 26 | d = p.data + off * (p.datasz + 8*p.ptrs); 27 | return FLIP(*(UINT_T*)d); 28 | 29 | case CAPN_PTR_LIST: 30 | d = struct_ptr(p.seg, p.data + 8*off, SZ/8); 31 | if (d) { 32 | return FLIP(*(UINT_T*)d); 33 | } else { 34 | return 0; 35 | } 36 | 37 | default: 38 | return 0; 39 | } 40 | } 41 | 42 | int CAT(capn_getv,SZ) (LIST_T l, int off, UINT_T *to, int sz) { 43 | int i; 44 | capn_ptr p; 45 | capn_resolve(&l.p); 46 | p = l.p; 47 | if (off + sz > p.len) { 48 | sz = p.len - off; 49 | } 50 | 51 | switch (p.type) { 52 | case CAPN_LIST: 53 | if (p.datasz == SZ/8 && !p.ptrs && (SZ == 8 || CAPN_LITTLE)) { 54 | memcpy(to, p.data + off, sz * (SZ/8)); 55 | return sz; 56 | } else if (p.datasz < SZ/8) { 57 | return -1; 58 | } 59 | 60 | for (i = 0; i < sz; i++) { 61 | char *d = p.data + (i + off) * (p.datasz + 8*p.ptrs); 62 | to[i] = FLIP(*(UINT_T*)d); 63 | } 64 | return sz; 65 | 66 | case CAPN_PTR_LIST: 67 | for (i = 0; i < sz; i++) { 68 | char *d = struct_ptr(p.seg, p.data + 8*(i+off), SZ/8); 69 | if (d) { 70 | to[i] = FLIP(*(UINT_T*)d); 71 | } else { 72 | return -1; 73 | } 74 | } 75 | return sz; 76 | 77 | default: 78 | return -1; 79 | } 80 | } 81 | 82 | int CAT(capn_set,SZ) (LIST_T l, int off, UINT_T v) { 83 | char *d; 84 | capn_ptr p = l.p; 85 | if (off >= p.len) { 86 | return -1; 87 | } 88 | 89 | switch (p.type) { 90 | case CAPN_LIST: 91 | if (p.datasz < SZ/8) 92 | return -1; 93 | d = p.data + off * (p.datasz + 8*p.ptrs); 94 | *(UINT_T*) d = FLIP(v); 95 | return 0; 96 | 97 | case CAPN_PTR_LIST: 98 | d = struct_ptr(p.seg, p.data + 8*off, SZ/8); 99 | if (!d) { 100 | return -1; 101 | } 102 | *(UINT_T*) d = FLIP(v); 103 | return 0; 104 | 105 | default: 106 | return -1; 107 | } 108 | } 109 | 110 | int CAT(capn_setv,SZ) (LIST_T l, int off, const UINT_T *from, int sz) { 111 | int i; 112 | capn_ptr p = l.p; 113 | if (off + sz > p.len) { 114 | sz = p.len - off; 115 | } 116 | 117 | switch (p.type) { 118 | case CAPN_LIST: 119 | if (p.datasz == SZ/8 && !p.ptrs && (SZ == 8 || CAPN_LITTLE)) { 120 | memcpy(p.data + off, from, sz * (SZ/8)); 121 | return sz; 122 | } else if (p.datasz < SZ/8) { 123 | return -1; 124 | } 125 | 126 | for (i = 0; i < sz; i++) { 127 | char *d = p.data + (i + off) * (p.datasz + 8*p.ptrs); 128 | *(UINT_T*) d = FLIP(from[i]); 129 | } 130 | return sz; 131 | 132 | case CAPN_PTR_LIST: 133 | for (i = 0; i < sz; i++) { 134 | char *d = struct_ptr(p.seg, p.data + 8*(i+off), SZ/8); 135 | if (d) { 136 | *(UINT_T*) d = FLIP(from[i]); 137 | } else { 138 | return -1; 139 | } 140 | } 141 | return sz; 142 | 143 | default: 144 | return -1; 145 | } 146 | } 147 | 148 | LIST_T CAT(capn_new_list,SZ) (struct capn_segment *seg, int sz) { 149 | LIST_T l = {{CAPN_LIST}}; 150 | l.p.seg = seg; 151 | l.p.len = sz; 152 | l.p.datasz = SZ/8; 153 | new_object(&l.p, sz*(SZ/8)); 154 | return l; 155 | } 156 | 157 | #undef CAT2 158 | #undef CAT 159 | #undef UINT_T 160 | #undef LIST_T 161 | #undef FLIP 162 | 163 | -------------------------------------------------------------------------------- /tests/addressbook.capnp.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPN_9EB32E19F86EE174 2 | #define CAPN_9EB32E19F86EE174 3 | /* AUTO GENERATED - DO NOT EDIT */ 4 | #include 5 | 6 | #if CAPN_VERSION != 1 7 | #error "version mismatch between capnp_c.h and generated code" 8 | #endif 9 | 10 | #include "c.capnp.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | struct Person; 17 | struct Person_PhoneNumber; 18 | struct AddressBook; 19 | 20 | typedef struct {capn_ptr p;} Person_ptr; 21 | typedef struct {capn_ptr p;} Person_PhoneNumber_ptr; 22 | typedef struct {capn_ptr p;} AddressBook_ptr; 23 | 24 | typedef struct {capn_ptr p;} Person_list; 25 | typedef struct {capn_ptr p;} Person_PhoneNumber_list; 26 | typedef struct {capn_ptr p;} AddressBook_list; 27 | 28 | enum Person_PhoneNumber_Type { 29 | Person_PhoneNumber_Type_mobile = 0, 30 | Person_PhoneNumber_Type_home = 1, 31 | Person_PhoneNumber_Type_work = 2 32 | }; 33 | enum Person_employment_which { 34 | Person_employment_unemployed = 0, 35 | Person_employment_employer = 1, 36 | Person_employment_school = 2, 37 | Person_employment_selfEmployed = 3 38 | }; 39 | 40 | struct Person { 41 | uint32_t id; 42 | capn_text name; 43 | capn_text email; 44 | Person_PhoneNumber_list phones; 45 | enum Person_employment_which employment_which; 46 | union { 47 | capn_text employer; 48 | capn_text school; 49 | } employment; 50 | }; 51 | 52 | static const size_t Person_word_count = 1; 53 | 54 | static const size_t Person_pointer_count = 4; 55 | 56 | static const size_t Person_struct_bytes_count = 40; 57 | 58 | uint32_t Person_get_id(Person_ptr p); 59 | 60 | capn_text Person_get_name(Person_ptr p); 61 | 62 | capn_text Person_get_email(Person_ptr p); 63 | 64 | Person_PhoneNumber_list Person_get_phones(Person_ptr p); 65 | 66 | void Person_set_id(Person_ptr p, uint32_t id); 67 | 68 | void Person_set_name(Person_ptr p, capn_text name); 69 | 70 | void Person_set_email(Person_ptr p, capn_text email); 71 | 72 | void Person_set_phones(Person_ptr p, Person_PhoneNumber_list phones); 73 | 74 | struct Person_PhoneNumber { 75 | capn_text number; 76 | enum Person_PhoneNumber_Type type; 77 | }; 78 | 79 | static const size_t Person_PhoneNumber_word_count = 1; 80 | 81 | static const size_t Person_PhoneNumber_pointer_count = 1; 82 | 83 | static const size_t Person_PhoneNumber_struct_bytes_count = 16; 84 | 85 | capn_text Person_PhoneNumber_get_number(Person_PhoneNumber_ptr p); 86 | 87 | enum Person_PhoneNumber_Type Person_PhoneNumber_get_type(Person_PhoneNumber_ptr p); 88 | 89 | void Person_PhoneNumber_set_number(Person_PhoneNumber_ptr p, capn_text number); 90 | 91 | void Person_PhoneNumber_set_type(Person_PhoneNumber_ptr p, enum Person_PhoneNumber_Type type); 92 | 93 | struct AddressBook { 94 | Person_list people; 95 | }; 96 | 97 | static const size_t AddressBook_word_count = 0; 98 | 99 | static const size_t AddressBook_pointer_count = 1; 100 | 101 | static const size_t AddressBook_struct_bytes_count = 8; 102 | 103 | Person_list AddressBook_get_people(AddressBook_ptr p); 104 | 105 | void AddressBook_set_people(AddressBook_ptr p, Person_list people); 106 | 107 | Person_ptr new_Person(struct capn_segment*); 108 | Person_PhoneNumber_ptr new_Person_PhoneNumber(struct capn_segment*); 109 | AddressBook_ptr new_AddressBook(struct capn_segment*); 110 | 111 | Person_list new_Person_list(struct capn_segment*, int len); 112 | Person_PhoneNumber_list new_Person_PhoneNumber_list(struct capn_segment*, int len); 113 | AddressBook_list new_AddressBook_list(struct capn_segment*, int len); 114 | 115 | void read_Person(struct Person*, Person_ptr); 116 | void read_Person_PhoneNumber(struct Person_PhoneNumber*, Person_PhoneNumber_ptr); 117 | void read_AddressBook(struct AddressBook*, AddressBook_ptr); 118 | 119 | void write_Person(const struct Person*, Person_ptr); 120 | void write_Person_PhoneNumber(const struct Person_PhoneNumber*, Person_PhoneNumber_ptr); 121 | void write_AddressBook(const struct AddressBook*, AddressBook_ptr); 122 | 123 | void get_Person(struct Person*, Person_list, int i); 124 | void get_Person_PhoneNumber(struct Person_PhoneNumber*, Person_PhoneNumber_list, int i); 125 | void get_AddressBook(struct AddressBook*, AddressBook_list, int i); 126 | 127 | void set_Person(const struct Person*, Person_list, int i); 128 | void set_Person_PhoneNumber(const struct Person_PhoneNumber*, Person_PhoneNumber_list, int i); 129 | void set_AddressBook(const struct AddressBook*, AddressBook_list, int i); 130 | 131 | #ifdef __cplusplus 132 | } 133 | #endif 134 | #endif 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | capnpc-c 2 | ======== 3 | 4 | This is a C plugin for [Cap'n Proto](http://kentonv.github.io/capnproto), an 5 | efficient protocol for sharing data and capabilities. 6 | 7 | ## UNMAINTAINED 8 | 9 | This project is currently **NOT MAINTAINED**. If you are interested in 10 | taking over maintenance and/or need this for some project, please look at 11 | issue https://github.com/opensourcerouting/c-capnproto/issues/55 12 | 13 | No releases will be made. PRs may sit unreviewed for multiple years. **PRs 14 | MAY get merged WITHOUT ANY REVIEW, as a last ditch attempt to not waste 15 | people's efforts on PRs. This means things may break completely.** 16 | 17 | > ## Security warning! 18 | 19 | > The generated code assumes all input to be trusted. Do NOT use with 20 | > untrusted input! There is currently no code in place to check if 21 | > structures/pointers are within bounds. 22 | 23 | This is only the code generator plugin, to properly make use of it you 24 | need to download, build and install capnpc and then build and install 25 | this project and then you can utilize it as: 26 | 27 | ```sh 28 | capnpc compiler/test.capnp -oc 29 | ``` 30 | 31 | [![Build Status](https://travis-ci.org/opensourcerouting/c-capnproto.svg?branch=master)](https://travis-ci.org/opensourcerouting/c-capnproto) 32 | 33 | ## Building on Linux 34 | 35 | ```sh 36 | git clone --recurse-submodules https://github.com/opensourcerouting/c-capnproto 37 | cd c-capnproto 38 | autoreconf -f -i -s 39 | ./configure 40 | make 41 | make check 42 | ``` 43 | 44 | ## Building with Meson 45 | 46 | ```sh 47 | git clone --recurse-submodules https://github.com/opensourcerouting/c-capnproto 48 | cd c-capnproto 49 | meson setup build 50 | meson compile -C build 51 | build/capn-test 52 | ``` 53 | 54 | ## Usage 55 | 56 | ### Generating C code from a `.capnp` schema file 57 | 58 | The `compiler` directory contains the C language plugin (`capnpc-c`) for use with the `capnp` tool: https://capnproto.org/capnp-tool.html. 59 | 60 | `capnp` will by default search `$PATH` for `capnpc-c` - if it's on your PATH, you can generate code for your schema as follows: 61 | 62 | ```sh 63 | capnp compile -o c myschema.capnp 64 | ``` 65 | 66 | Otherwise, you can specify the path to the c plugin: 67 | 68 | ```sh 69 | capnp compile -o ./capnpc-c myschema.capnp 70 | ``` 71 | 72 | `capnp` generates a C struct that corresponds to each capn proto struct, along with read/write functions that convert to/from capn proto form. 73 | 74 | If you want accessor functions for struct members, use attribute `fieldgetset` in your `.capnp` file as follows: 75 | 76 | ```capnp 77 | using C = import "${c-capnproto}/compiler/c.capnp"; 78 | 79 | $C.fieldgetset; 80 | 81 | struct MyStruct {} 82 | ``` 83 | 84 | ### Example C code 85 | 86 | See the unit tests in [`tests/example-test.cpp`](tests/example-test.cpp). 87 | The example schema file is [`tests/addressbook.capnp`](tests/addressbook.capnp). 88 | The tests are written in C++, but only use C features. 89 | 90 | You need to compile these runtime library files and link them into your own project's binaries: 91 | 92 | * [`lib/capn.c`](lib/capn.c) 93 | * [`lib/capn-malloc.c`](lib/capn-malloc.c) 94 | * [`lib/capn-stream.c`](lib/capn-stream.c) 95 | 96 | Your include path must contain the runtime library directory 97 | [`lib`](lib). Header file [`lib/capnp_c.h`](lib/capnp_c.h) contains 98 | the public interfaces of the library. 99 | 100 | Using make-based builds, make may try to compile `${x}.capnp` from 101 | `${x}.capnp.c` using its built-in rule for compiling `${y}` from 102 | `${y}.c`. You can either disable make's built-in compile rules or just 103 | this specific case with the no-op rule: `%.capnp: ;`. 104 | 105 | For further reference, please see the other unit tests in [`tests`](tests), and header file [`lib/capnp_c.h`](lib/capnp_c.h). 106 | 107 | The project [`quagga-capnproto`](https://github.com/opensourcerouting/quagga-capnproto) uses `c-capnproto` and contains some good examples, as found with [this github repository search](https://github.com/opensourcerouting/quagga-capnproto/search?utf8=%E2%9C%93&q=capn&type=): 108 | 109 | * Serialization in function [`bgp_notify_send()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/bgpd/bgp_zmq.c#L81-L96) in file `quagga-capnproto/bgpd/bgp_zmq.c` 110 | * Deserialization in function [`qzc_callback()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/lib/qzc.c#L249-L257) in file `quagga-capnproto/lib/qzc.c` 111 | 112 | ## Status 113 | 114 | This is a merge of 3 forks of [James McKaskill's great 115 | work](https://github.com/jmckaskill/c-capnproto), which has been untouched for 116 | a while: 117 | 118 | - [liamstask's fork](https://github.com/liamstask/c-capnproto) 119 | - [baruch's fork](https://github.com/baruch/c-capnproto) 120 | - [kylemanna's fork](https://github.com/kylemanna/c-capnproto) 121 | -------------------------------------------------------------------------------- /lib/capn-stream.c: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* capn-stream.c 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * 6 | * This software may be modified and distributed under the terms 7 | * of the MIT license. See the LICENSE file for details. 8 | */ 9 | 10 | #include "capnp_c.h" 11 | #include "capnp_priv.h" 12 | #include 13 | 14 | #ifndef min 15 | static unsigned min(unsigned a, unsigned b) { return (a < b) ? a : b; } 16 | #endif 17 | 18 | int capn_deflate(struct capn_stream* s) { 19 | if (s->avail_in % 8) { 20 | return CAPN_MISALIGNED; 21 | } 22 | 23 | while (s->avail_in) { 24 | int i; 25 | size_t sz; 26 | uint8_t hdr = 0; 27 | uint8_t *p; 28 | 29 | if (!s->avail_out) 30 | return CAPN_NEED_MORE; 31 | 32 | if (s->raw > 0) { 33 | sz = min(s->raw, min(s->avail_in, s->avail_out)); 34 | memcpy(s->next_out, s->next_in, sz); 35 | s->next_out += sz; 36 | s->next_in += sz; 37 | s->avail_out -= sz; 38 | s->avail_in -= sz; 39 | s->raw -= sz; 40 | continue; 41 | } 42 | 43 | if (s->avail_in < 8) 44 | return CAPN_NEED_MORE; 45 | 46 | sz = 0; 47 | for (i = 0; i < 8; i++) { 48 | if (s->next_in[i]) { 49 | sz ++; 50 | hdr |= 1 << i; 51 | } 52 | } 53 | 54 | switch (sz) { 55 | case 0: 56 | if (s->avail_out < 2) 57 | return CAPN_NEED_MORE; 58 | 59 | s->next_out[0] = 0; 60 | for (sz = 1; sz < min(s->avail_in/8, 256); sz++) { 61 | if (((uint64_t*) s->next_in)[sz] != 0) { 62 | break; 63 | } 64 | } 65 | 66 | s->next_out[1] = (uint8_t) (sz-1); 67 | s->next_in += sz*8; 68 | s->avail_in -= sz*8; 69 | s->next_out += 2; 70 | s->avail_out -= 2; 71 | continue; 72 | 73 | case 8: 74 | if (s->avail_out < 10) 75 | return CAPN_NEED_MORE; 76 | 77 | s->next_out[0] = 0xFF; 78 | memcpy(s->next_out+1, s->next_in, 8); 79 | s->next_in += 8; 80 | s->avail_in -= 8; 81 | 82 | s->raw = min(s->avail_in, 256*8); 83 | if ((p = (uint8_t*) memchr(s->next_in, 0, s->raw)) != NULL) { 84 | s->raw = (p - s->next_in) & ~7; 85 | } 86 | 87 | s->next_out[9] = (uint8_t) (s->raw/8); 88 | s->next_out += 10; 89 | s->avail_out -= 10; 90 | continue; 91 | 92 | default: 93 | if (s->avail_out < 1U + sz) 94 | return CAPN_NEED_MORE; 95 | 96 | *(s->next_out++) = hdr; 97 | for (i = 0; i < 8; i++) { 98 | if (s->next_in[i]) { 99 | *(s->next_out++) = s->next_in[i]; 100 | } 101 | } 102 | s->avail_out -= sz + 1; 103 | s->next_in += 8; 104 | s->avail_in -= 8; 105 | continue; 106 | } 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | int capn_inflate(struct capn_stream* s) { 113 | while (s->avail_out) { 114 | int i; 115 | size_t sz; 116 | uint8_t hdr; 117 | uint8_t *wr; 118 | 119 | if (s->avail_buf && s->avail_out >= s->avail_buf) { 120 | memcpy(s->next_out, s->inflate_buf, s->avail_buf); 121 | s->next_out += s->avail_buf; 122 | s->avail_out -= s->avail_buf; 123 | s->avail_buf = 0; 124 | if (!s->avail_out) 125 | return 0; 126 | } 127 | if (s->avail_buf && s->avail_out < s->avail_buf) { 128 | memcpy(s->next_out, s->inflate_buf, s->avail_out); 129 | memmove(s->inflate_buf, s->inflate_buf + s->avail_out, 130 | s->avail_buf - s->avail_out); 131 | s->avail_buf -= s->avail_out; 132 | s->avail_out = 0; 133 | return 0; 134 | } 135 | 136 | if (s->zeros > 0) { 137 | sz = min(s->avail_out, s->zeros); 138 | memset(s->next_out, 0, sz); 139 | s->next_out += sz; 140 | s->avail_out -= sz; 141 | s->zeros -= sz; 142 | continue; 143 | } 144 | 145 | if (s->raw > 0) { 146 | if (s->avail_in == 0) 147 | return CAPN_NEED_MORE; 148 | 149 | sz = min(min(s->avail_out, s->raw), s->avail_in); 150 | memcpy(s->next_out, s->next_in, sz); 151 | s->next_in += sz; 152 | s->next_out += sz; 153 | s->avail_in -= sz; 154 | s->avail_out -= sz; 155 | s->raw -= sz; 156 | continue; 157 | } 158 | 159 | if (s->avail_in == 0) 160 | return 0; 161 | else if (s->avail_in < 2) 162 | return CAPN_NEED_MORE; 163 | 164 | switch (s->next_in[0]) { 165 | case 0xFF: 166 | /* 0xFF is followed by 8 bytes raw, followed by 167 | * a byte with length in words to read raw */ 168 | if (s->avail_in < 10) 169 | return CAPN_NEED_MORE; 170 | 171 | memcpy(s->inflate_buf, s->next_in+1, 8); 172 | s->avail_buf = 8; 173 | 174 | s->raw = s->next_in[9] * 8; 175 | s->next_in += 10; 176 | s->avail_in -= 10; 177 | continue; 178 | 179 | case 0x00: 180 | /* 0x00 is followed by a single byte indicating 181 | * the count of consecutive zero value words 182 | * minus 1 */ 183 | s->zeros = (s->next_in[1] + 1) * 8; 184 | s->next_in += 2; 185 | s->avail_in -= 2; 186 | continue; 187 | 188 | default: 189 | hdr = s->next_in[0]; 190 | sz = 0; 191 | for (i = 0; i < 8; i++) { 192 | if (hdr & (1 << i)) 193 | sz++; 194 | } 195 | if (s->avail_in < 1U + sz) 196 | return CAPN_NEED_MORE; 197 | 198 | s->next_in += 1; 199 | 200 | wr = s->inflate_buf; 201 | for (i = 0; i < 8; i++) { 202 | if (hdr & (1 << i)) { 203 | *wr++ = *s->next_in++; 204 | } else { 205 | *wr++ = 0; 206 | } 207 | } 208 | 209 | s->avail_buf = 8; 210 | s->avail_in -= 1 + sz; 211 | continue; 212 | } 213 | } 214 | 215 | return 0; 216 | } 217 | 218 | -------------------------------------------------------------------------------- /tests/example-test.cpp: -------------------------------------------------------------------------------- 1 | /* example-test.cpp 2 | * 3 | * Some simple examples using c-capnproto. 4 | * 5 | * Based on the addressbook.capnp example in the capnproto C++ project: 6 | * https://github.com/sandstorm-io/capnproto/blob/6816634a08b08bc8f52b4ee809afb58389f19655/c%2B%2B/samples/addressbook.capnp 7 | * 8 | * Copyright (C) 2017 Alex Helfet 9 | * 10 | * This software may be modified and distributed under the terms 11 | * of the MIT license. See the LICENSE file for details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | #include "capnp_c.h" 18 | #include "addressbook.capnp.h" 19 | 20 | static capn_text chars_to_text(const char *chars) { 21 | return (capn_text) { 22 | .len = (int) strlen(chars), 23 | .str = chars, 24 | .seg = NULL, 25 | }; 26 | } 27 | 28 | // EXPECT_CAPN_TEXT_EQ arguments: 29 | // const char * expected 30 | // capn_text t 31 | #define EXPECT_CAPN_TEXT_EQ(expected, t) \ 32 | do { \ 33 | EXPECT_EQ(strlen((expected)), (uint32_t) (t).len); \ 34 | EXPECT_STREQ((expected), (t).str); \ 35 | } while(0); 36 | 37 | 38 | // Demonstrates serializing an object tree to a byte array, then deserializing it 39 | // back into an object tree and asserting on the expected values therein. 40 | // 41 | // This example uses generated read_*, write_*, get_*, set_* functions 42 | // to deserialize into structs. 43 | TEST(Examples, RoundTripPerson) { 44 | uint8_t buf[4096]; 45 | ssize_t sz = 0; 46 | 47 | const char *name = "Firstname Lastname"; 48 | const char *email = "username@domain.com"; 49 | const char *school = "of life"; 50 | 51 | { 52 | struct capn c; 53 | capn_init_malloc(&c); 54 | capn_ptr cr = capn_root(&c); 55 | struct capn_segment *cs = cr.seg; 56 | 57 | // Set initial object in `p`. 58 | struct Person p = { 59 | .id = 17, 60 | .name = chars_to_text(name), 61 | .email = chars_to_text(email), 62 | }; 63 | p.employment_which = Person_employment_school; 64 | p.employment.school = chars_to_text(school); 65 | 66 | p.phones = new_Person_PhoneNumber_list(cs, 2); 67 | struct Person_PhoneNumber pn0 = { 68 | .number = chars_to_text("123"), 69 | .type = Person_PhoneNumber_Type_work, 70 | }; 71 | set_Person_PhoneNumber(&pn0, p.phones, 0); 72 | struct Person_PhoneNumber pn1 = { 73 | .number = chars_to_text("234"), 74 | .type = Person_PhoneNumber_Type_home, 75 | }; 76 | set_Person_PhoneNumber(&pn1, p.phones, 1); 77 | 78 | Person_ptr pp = new_Person(cs); 79 | write_Person(&p, pp); 80 | int setp_ret = capn_setp(capn_root(&c), 0, pp.p); 81 | ASSERT_EQ(0, setp_ret); 82 | sz = capn_write_mem(&c, buf, sizeof(buf), 0 /* packed */); 83 | capn_free(&c); 84 | } 85 | 86 | { 87 | // Write serialized object to file system. 88 | FILE *f = fopen("tests/example-test.cpp.Person.out", "wb"); 89 | ASSERT_NE(f, (void*)0); 90 | fwrite(buf, 1 /* size */, sz /* count */, f); 91 | int close_ret = fclose(f); 92 | ASSERT_EQ(0, close_ret); 93 | } 94 | 95 | { 96 | // Deserialize `buf[0..sz-1]` to `rp`. 97 | struct capn rc; 98 | int init_mem_ret = capn_init_mem(&rc, buf, sz, 0 /* packed */); 99 | ASSERT_EQ(0, init_mem_ret); 100 | Person_ptr rroot; 101 | struct Person rp; 102 | rroot.p = capn_getp(capn_root(&rc), 0 /* off */, 1 /* resolve */); 103 | read_Person(&rp, rroot); 104 | 105 | // Assert deserialized values in `rp` 106 | EXPECT_EQ(rp.id, (uint32_t) 17); 107 | EXPECT_CAPN_TEXT_EQ(name, rp.name); 108 | EXPECT_CAPN_TEXT_EQ(email, rp.email); 109 | 110 | EXPECT_EQ(rp.employment_which, Person_employment_school); 111 | EXPECT_CAPN_TEXT_EQ(school, rp.employment.school); 112 | 113 | EXPECT_EQ(2, capn_len(rp.phones)); 114 | 115 | struct Person_PhoneNumber rpn0; 116 | get_Person_PhoneNumber(&rpn0, rp.phones, 0); 117 | EXPECT_CAPN_TEXT_EQ("123", rpn0.number); 118 | EXPECT_EQ(rpn0.type, Person_PhoneNumber_Type_work); 119 | 120 | struct Person_PhoneNumber rpn1; 121 | get_Person_PhoneNumber(&rpn1, rp.phones, 1); 122 | EXPECT_CAPN_TEXT_EQ("234", rpn1.number); 123 | EXPECT_EQ(rpn1.type, Person_PhoneNumber_Type_home); 124 | 125 | capn_free(&rc); 126 | } 127 | } 128 | 129 | // Demonstrate accessing serialized objects using accessor functions without 130 | // first copying values into structs. 131 | TEST(Examples, PersonWithAccessors) { 132 | struct capn c; 133 | capn_init_malloc(&c); 134 | capn_ptr cr = capn_root(&c); 135 | struct capn_segment *cs = cr.seg; 136 | 137 | // Set fields with set_ accessors. 138 | Person_ptr pp = new_Person(cs); 139 | { 140 | Person_set_id(pp, 17); 141 | 142 | capn_text name = chars_to_text("Name"); 143 | EXPECT_CAPN_TEXT_EQ("Name", name); 144 | Person_set_name(pp, name); 145 | 146 | Person_PhoneNumber_list pnl = new_Person_PhoneNumber_list(cs, 1); 147 | Person_set_phones(pp, pnl); 148 | Person_PhoneNumber_ptr pn0; 149 | pn0.p = capn_getp(pnl.p, 0 /* offset */, 0 /* resolve */); 150 | Person_PhoneNumber_set_type(pn0, Person_PhoneNumber_Type_home); 151 | } 152 | 153 | // Assert field values returned by get_ accessors. 154 | { 155 | EXPECT_EQ(Person_get_id(pp), 17); 156 | EXPECT_CAPN_TEXT_EQ("Name", Person_get_name(pp)); 157 | 158 | Person_PhoneNumber_list pnl = Person_get_phones(pp); 159 | Person_PhoneNumber_ptr pn0; 160 | pn0.p = capn_getp(pnl.p, 0 /* offset */, 0 /* resolve */); 161 | EXPECT_EQ(Person_PhoneNumber_Type_home, Person_PhoneNumber_get_type(pn0)); 162 | } 163 | 164 | capn_free(&c); 165 | } 166 | -------------------------------------------------------------------------------- /tests/addressbook.capnp.c: -------------------------------------------------------------------------------- 1 | #include "addressbook.capnp.h" 2 | /* AUTO GENERATED - DO NOT EDIT */ 3 | static const capn_text capn_val0 = {0,"",0}; 4 | 5 | Person_ptr new_Person(struct capn_segment *s) { 6 | Person_ptr p; 7 | p.p = capn_new_struct(s, 8, 4); 8 | return p; 9 | } 10 | Person_list new_Person_list(struct capn_segment *s, int len) { 11 | Person_list p; 12 | p.p = capn_new_list(s, len, 8, 4); 13 | return p; 14 | } 15 | void read_Person(struct Person *s, Person_ptr p) { 16 | capn_resolve(&p.p); 17 | s->id = capn_read32(p.p, 0); 18 | s->name = capn_get_text(p.p, 0, capn_val0); 19 | s->email = capn_get_text(p.p, 1, capn_val0); 20 | s->phones.p = capn_getp(p.p, 2, 0); 21 | s->employment_which = (enum Person_employment_which)(int) capn_read16(p.p, 4); 22 | switch (s->employment_which) { 23 | case Person_employment_employer: 24 | case Person_employment_school: 25 | s->employment.school = capn_get_text(p.p, 3, capn_val0); 26 | break; 27 | default: 28 | break; 29 | } 30 | } 31 | void write_Person(const struct Person *s, Person_ptr p) { 32 | capn_resolve(&p.p); 33 | capn_write32(p.p, 0, s->id); 34 | capn_set_text(p.p, 0, s->name); 35 | capn_set_text(p.p, 1, s->email); 36 | capn_setp(p.p, 2, s->phones.p); 37 | capn_write16(p.p, 4, s->employment_which); 38 | switch (s->employment_which) { 39 | case Person_employment_employer: 40 | case Person_employment_school: 41 | capn_set_text(p.p, 3, s->employment.school); 42 | break; 43 | default: 44 | break; 45 | } 46 | } 47 | void get_Person(struct Person *s, Person_list l, int i) { 48 | Person_ptr p; 49 | p.p = capn_getp(l.p, i, 0); 50 | read_Person(s, p); 51 | } 52 | void set_Person(const struct Person *s, Person_list l, int i) { 53 | Person_ptr p; 54 | p.p = capn_getp(l.p, i, 0); 55 | write_Person(s, p); 56 | } 57 | 58 | uint32_t Person_get_id(Person_ptr p) 59 | { 60 | uint32_t id; 61 | id = capn_read32(p.p, 0); 62 | return id; 63 | } 64 | 65 | capn_text Person_get_name(Person_ptr p) 66 | { 67 | capn_text name; 68 | name = capn_get_text(p.p, 0, capn_val0); 69 | return name; 70 | } 71 | 72 | capn_text Person_get_email(Person_ptr p) 73 | { 74 | capn_text email; 75 | email = capn_get_text(p.p, 1, capn_val0); 76 | return email; 77 | } 78 | 79 | Person_PhoneNumber_list Person_get_phones(Person_ptr p) 80 | { 81 | Person_PhoneNumber_list phones; 82 | phones.p = capn_getp(p.p, 2, 0); 83 | return phones; 84 | } 85 | 86 | void Person_set_id(Person_ptr p, uint32_t id) 87 | { 88 | capn_write32(p.p, 0, id); 89 | } 90 | 91 | void Person_set_name(Person_ptr p, capn_text name) 92 | { 93 | capn_set_text(p.p, 0, name); 94 | } 95 | 96 | void Person_set_email(Person_ptr p, capn_text email) 97 | { 98 | capn_set_text(p.p, 1, email); 99 | } 100 | 101 | void Person_set_phones(Person_ptr p, Person_PhoneNumber_list phones) 102 | { 103 | capn_setp(p.p, 2, phones.p); 104 | } 105 | 106 | Person_PhoneNumber_ptr new_Person_PhoneNumber(struct capn_segment *s) { 107 | Person_PhoneNumber_ptr p; 108 | p.p = capn_new_struct(s, 8, 1); 109 | return p; 110 | } 111 | Person_PhoneNumber_list new_Person_PhoneNumber_list(struct capn_segment *s, int len) { 112 | Person_PhoneNumber_list p; 113 | p.p = capn_new_list(s, len, 8, 1); 114 | return p; 115 | } 116 | void read_Person_PhoneNumber(struct Person_PhoneNumber *s, Person_PhoneNumber_ptr p) { 117 | capn_resolve(&p.p); 118 | s->number = capn_get_text(p.p, 0, capn_val0); 119 | s->type = (enum Person_PhoneNumber_Type)(int) capn_read16(p.p, 0); 120 | } 121 | void write_Person_PhoneNumber(const struct Person_PhoneNumber *s, Person_PhoneNumber_ptr p) { 122 | capn_resolve(&p.p); 123 | capn_set_text(p.p, 0, s->number); 124 | capn_write16(p.p, 0, (uint16_t) (s->type)); 125 | } 126 | void get_Person_PhoneNumber(struct Person_PhoneNumber *s, Person_PhoneNumber_list l, int i) { 127 | Person_PhoneNumber_ptr p; 128 | p.p = capn_getp(l.p, i, 0); 129 | read_Person_PhoneNumber(s, p); 130 | } 131 | void set_Person_PhoneNumber(const struct Person_PhoneNumber *s, Person_PhoneNumber_list l, int i) { 132 | Person_PhoneNumber_ptr p; 133 | p.p = capn_getp(l.p, i, 0); 134 | write_Person_PhoneNumber(s, p); 135 | } 136 | 137 | capn_text Person_PhoneNumber_get_number(Person_PhoneNumber_ptr p) 138 | { 139 | capn_text number; 140 | number = capn_get_text(p.p, 0, capn_val0); 141 | return number; 142 | } 143 | 144 | enum Person_PhoneNumber_Type Person_PhoneNumber_get_type(Person_PhoneNumber_ptr p) 145 | { 146 | enum Person_PhoneNumber_Type type; 147 | type = (enum Person_PhoneNumber_Type)(int) capn_read16(p.p, 0); 148 | return type; 149 | } 150 | 151 | void Person_PhoneNumber_set_number(Person_PhoneNumber_ptr p, capn_text number) 152 | { 153 | capn_set_text(p.p, 0, number); 154 | } 155 | 156 | void Person_PhoneNumber_set_type(Person_PhoneNumber_ptr p, enum Person_PhoneNumber_Type type) 157 | { 158 | capn_write16(p.p, 0, (uint16_t) (type)); 159 | } 160 | 161 | AddressBook_ptr new_AddressBook(struct capn_segment *s) { 162 | AddressBook_ptr p; 163 | p.p = capn_new_struct(s, 0, 1); 164 | return p; 165 | } 166 | AddressBook_list new_AddressBook_list(struct capn_segment *s, int len) { 167 | AddressBook_list p; 168 | p.p = capn_new_list(s, len, 0, 1); 169 | return p; 170 | } 171 | void read_AddressBook(struct AddressBook *s, AddressBook_ptr p) { 172 | capn_resolve(&p.p); 173 | s->people.p = capn_getp(p.p, 0, 0); 174 | } 175 | void write_AddressBook(const struct AddressBook *s, AddressBook_ptr p) { 176 | capn_resolve(&p.p); 177 | capn_setp(p.p, 0, s->people.p); 178 | } 179 | void get_AddressBook(struct AddressBook *s, AddressBook_list l, int i) { 180 | AddressBook_ptr p; 181 | p.p = capn_getp(l.p, i, 0); 182 | read_AddressBook(s, p); 183 | } 184 | void set_AddressBook(const struct AddressBook *s, AddressBook_list l, int i) { 185 | AddressBook_ptr p; 186 | p.p = capn_getp(l.p, i, 0); 187 | write_AddressBook(s, p); 188 | } 189 | 190 | Person_list AddressBook_get_people(AddressBook_ptr p) 191 | { 192 | Person_list people; 193 | people.p = capn_getp(p.p, 0, 0); 194 | return people; 195 | } 196 | 197 | void AddressBook_set_people(AddressBook_ptr p, Person_list people) 198 | { 199 | capn_setp(p.p, 0, people.p); 200 | } 201 | -------------------------------------------------------------------------------- /tests/capn-stream-test.cpp: -------------------------------------------------------------------------------- 1 | /* capn-stream-test.cpp 2 | * 3 | * Copyright (C) 2013 James McKaskill 4 | * Copyright (C) 2014 Steve Dee 5 | * 6 | * This software may be modified and distributed under the terms 7 | * of the MIT license. See the LICENSE file for details. 8 | */ 9 | 10 | #include "capn-stream.c" 11 | #include 12 | 13 | template 14 | union AlignedData { 15 | uint8_t bytes[wordCount * 8]; 16 | uint64_t words[wordCount]; 17 | }; 18 | 19 | TEST(Stream, ReadEmptyStream_Even) { 20 | AlignedData<2> data = {{ 21 | 1, 0, 0, 0, // num of segs - 1 22 | 0, 0, 0, 0, 23 | 0, 0, 0, 0, 24 | 2, 3, 4, 0, // garbage that should be ignored 25 | }}; 26 | 27 | struct capn ctx; 28 | ASSERT_NE(0, capn_init_mem(&ctx, data.bytes, 12, 0)); 29 | ASSERT_EQ(0, capn_init_mem(&ctx, data.bytes, 16, 0)); 30 | EXPECT_EQ(2, ctx.segnum); 31 | EXPECT_EQ(0, ctx.seglist->len); 32 | EXPECT_EQ(0, ctx.seglist->next->len); 33 | capn_free(&ctx); 34 | } 35 | 36 | TEST(Stream, ReadEmptyStream_Odd) { 37 | AlignedData<3> data = {{ 38 | 2, 0, 0, 0, // num of segs - 1 39 | 0, 0, 0, 0, 40 | 0, 0, 0, 0, 41 | 0, 0, 0, 0, 42 | 2, 3, 4, 0, // garbage that should be ignored 43 | }}; 44 | 45 | struct capn ctx; 46 | ASSERT_NE(0, capn_init_mem(&ctx, data.bytes, 12, 0)); 47 | 48 | ASSERT_EQ(0, capn_init_mem(&ctx, data.bytes, 16, 0)); 49 | EXPECT_EQ(3, ctx.segnum); 50 | EXPECT_EQ(0, ctx.seglist->len); 51 | EXPECT_EQ(0, ctx.seglist->next->len); 52 | capn_free(&ctx); 53 | 54 | ASSERT_EQ(0, capn_init_mem(&ctx, data.bytes, 20, 0)); 55 | EXPECT_EQ(3, ctx.segnum); 56 | EXPECT_EQ(0, ctx.seglist->len); 57 | EXPECT_EQ(0, ctx.seglist->next->len); 58 | capn_free(&ctx); 59 | } 60 | 61 | TEST(Stream, ReadStream_Even) { 62 | AlignedData<5> data = {{ 63 | 1, 0, 0, 0, // num of segs - 1 64 | 1, 0, 0, 0, 65 | 2, 0, 0, 0, 66 | 2, 3, 4, 0, // garbage that should be ignored 67 | 1, 2, 3, 4, 5, 6, 7, 8, 68 | 9,10,11,12,13,14,15,16, 69 | 17,18,19,20,21,22,23,24, 70 | }}; 71 | 72 | struct capn ctx; 73 | ASSERT_NE(0, capn_init_mem(&ctx, data.bytes, 36, 0)); 74 | ASSERT_EQ(0, capn_init_mem(&ctx, data.bytes, 40, 0)); 75 | EXPECT_EQ(2, ctx.segnum); 76 | EXPECT_EQ(8, ctx.seglist->len); 77 | EXPECT_EQ(1, ctx.seglist->data[0]); 78 | EXPECT_EQ(16, ctx.seglist->next->len); 79 | EXPECT_EQ(9, ctx.seglist->next->data[0]); 80 | capn_free(&ctx); 81 | } 82 | 83 | static struct capn_segment *CreateSmallSegment(void *u, uint32_t id, int sz) { 84 | struct capn_segment *s = (struct capn_segment*) calloc(1, sizeof(*s)); 85 | s->data = (char*) calloc(1, sz); 86 | s->cap = sz; 87 | return s; 88 | } 89 | 90 | TEST(Stream, SizeEmptyStream) { 91 | struct capn ctx; 92 | capn_init_malloc(&ctx); 93 | struct capn_ptr root = capn_root(&ctx); 94 | ASSERT_EQ(CAPN_PTR_LIST, root.type); 95 | EXPECT_EQ(2*8, capn_size(&ctx)); 96 | 97 | capn_free(&ctx); 98 | } 99 | 100 | TEST(Stream, SizeOneSegment) { 101 | struct capn ctx; 102 | capn_init_malloc(&ctx); 103 | struct capn_ptr root = capn_root(&ctx); 104 | struct capn_ptr ptr = capn_new_struct(root.seg, 8, 0); 105 | EXPECT_EQ(0, capn_setp(root, 0, ptr)); 106 | EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); 107 | EXPECT_EQ(3*8, capn_size(&ctx)); 108 | 109 | capn_free(&ctx); 110 | } 111 | 112 | TEST(Stream, SizeTwoSegments) { 113 | struct capn ctx; 114 | capn_init_malloc(&ctx); 115 | ctx.create = &CreateSmallSegment; 116 | struct capn_ptr root = capn_root(&ctx); 117 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 8, 0); 118 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 119 | EXPECT_EQ(0, capn_write64(ptr1, 0, UINT64_C(0xfffefdfcfbfaf9f8))); 120 | EXPECT_EQ(2, ctx.segnum); 121 | 122 | /* 2 words: header 123 | * 1 word: segment 1 124 | * 2 words: segment 2 125 | */ 126 | EXPECT_EQ(5*8, capn_size(&ctx)); 127 | 128 | capn_free(&ctx); 129 | } 130 | 131 | TEST(Stream, SizeThreeSegments) { 132 | struct capn ctx; 133 | capn_init_malloc(&ctx); 134 | ctx.create = &CreateSmallSegment; 135 | struct capn_ptr root = capn_root(&ctx); 136 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 0, 1); 137 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 138 | struct capn_ptr ptr2 = capn_new_struct(ptr1.seg, 4, 0); 139 | EXPECT_EQ(0, capn_setp(ptr1, 0, ptr2)); 140 | EXPECT_EQ(0, capn_write32(ptr2, 0, 0x12345678)); 141 | EXPECT_EQ(3, ctx.segnum); 142 | 143 | EXPECT_EQ(7*8, capn_size(&ctx)); 144 | 145 | capn_free(&ctx); 146 | } 147 | 148 | TEST(Stream, WriteEmptyStream) { 149 | uint8_t buf[2048]; 150 | 151 | struct capn ctx1, ctx2; 152 | capn_init_malloc(&ctx1); 153 | struct capn_ptr root = capn_root(&ctx1); 154 | ASSERT_EQ(CAPN_PTR_LIST, root.type); 155 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 2*8-1, 0)); 156 | EXPECT_EQ(2*8, capn_write_mem(&ctx1, buf, 2048, 0)); 157 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); 158 | EXPECT_EQ(1, ctx2.segnum); 159 | EXPECT_EQ(8, ctx2.seglist->len); 160 | EXPECT_EQ(0, ctx2.seglist->next); 161 | 162 | capn_free(&ctx1); 163 | capn_free(&ctx2); 164 | } 165 | 166 | TEST(Stream, WriteEmptyStreamPacked) { 167 | uint8_t buf[2048]; 168 | 169 | struct capn ctx1, ctx2; 170 | capn_init_malloc(&ctx1); 171 | struct capn_ptr root = capn_root(&ctx1); 172 | ASSERT_EQ(CAPN_PTR_LIST, root.type); 173 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 3, 1)); 174 | EXPECT_EQ(4, capn_write_mem(&ctx1, buf, 2048, 1)); 175 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 1)); 176 | EXPECT_EQ(1, ctx2.segnum); 177 | EXPECT_EQ(8, ctx2.seglist->len); 178 | EXPECT_EQ(0, ctx2.seglist->next); 179 | 180 | capn_free(&ctx1); 181 | capn_free(&ctx2); 182 | } 183 | 184 | TEST(Stream, WriteOneSegment) { 185 | uint8_t buf[2048]; 186 | 187 | struct capn ctx1, ctx2; 188 | capn_init_malloc(&ctx1); 189 | 190 | struct capn_ptr root = capn_root(&ctx1); 191 | struct capn_ptr ptr = capn_new_struct(root.seg, 8, 0); 192 | EXPECT_EQ(0, capn_setp(root, 0, ptr)); 193 | EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); 194 | 195 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 3*8-1, 0)); 196 | EXPECT_EQ(3*8, capn_write_mem(&ctx1, buf, 2048, 0)); 197 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); 198 | EXPECT_EQ(1, ctx2.segnum); 199 | 200 | root = capn_root(&ctx2); 201 | ptr = capn_getp(root, 0, 1); 202 | EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0)); 203 | 204 | capn_free(&ctx1); 205 | capn_free(&ctx2); 206 | } 207 | 208 | TEST(Stream, WriteOneSegmentPacked) { 209 | uint8_t buf[2048]; 210 | 211 | struct capn ctx1, ctx2; 212 | capn_init_malloc(&ctx1); 213 | 214 | struct capn_ptr root = capn_root(&ctx1); 215 | struct capn_ptr ptr = capn_new_struct(root.seg, 8, 0); 216 | EXPECT_EQ(0, capn_setp(root, 0, ptr)); 217 | EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); 218 | 219 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 13, 1)); 220 | EXPECT_EQ(14, capn_write_mem(&ctx1, buf, 2048, 1)); 221 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 1)); 222 | EXPECT_EQ(1, ctx2.segnum); 223 | 224 | root = capn_root(&ctx2); 225 | ptr = capn_getp(root, 0, 1); 226 | EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0)); 227 | 228 | capn_free(&ctx1); 229 | capn_free(&ctx2); 230 | } 231 | 232 | TEST(Stream, WriteTwoSegments) { 233 | struct capn ctx1, ctx2; 234 | uint8_t buf[5*8]; 235 | 236 | capn_init_malloc(&ctx1); 237 | ctx1.create = &CreateSmallSegment; 238 | struct capn_ptr root = capn_root(&ctx1); 239 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 8, 0); 240 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 241 | EXPECT_EQ(0, capn_write64(ptr1, 0, UINT64_C(0xfffefdfcfbfaf9f8))); 242 | EXPECT_EQ(2, ctx1.segnum); 243 | 244 | /* 2 words: header 245 | * 1 word: segment 1 246 | * 2 words: segment 2 247 | */ 248 | EXPECT_EQ(5*8, capn_write_mem(&ctx1, buf, 5*8, 0)); 249 | 250 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); 251 | root = capn_root(&ctx2); 252 | ptr1 = capn_getp(root, 0, 1); 253 | EXPECT_EQ(UINT64_C(0xfffefdfcfbfaf9f8), capn_read64(ptr1, 0)); 254 | 255 | capn_free(&ctx1); 256 | capn_free(&ctx2); 257 | } 258 | 259 | TEST(Stream, WriteTwoSegmentsPacked) { 260 | struct capn ctx1, ctx2; 261 | uint8_t buf[5*8]; 262 | 263 | capn_init_malloc(&ctx1); 264 | ctx1.create = &CreateSmallSegment; 265 | struct capn_ptr root = capn_root(&ctx1); 266 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 8, 0); 267 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 268 | EXPECT_EQ(0, capn_write64(ptr1, 0, UINT64_C(0xfffefdfcfbfaf9f8))); 269 | EXPECT_EQ(2, ctx1.segnum); 270 | 271 | /* 2 words: header 272 | * 1 word: segment 1 273 | * 2 words: segment 2 274 | */ 275 | EXPECT_EQ(20, capn_write_mem(&ctx1, buf, 5*8, 1)); 276 | 277 | ASSERT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 1)); 278 | root = capn_root(&ctx2); 279 | ptr1 = capn_getp(root, 0, 1); 280 | EXPECT_EQ(UINT64_C(0xfffefdfcfbfaf9f8), capn_read64(ptr1, 0)); 281 | 282 | capn_free(&ctx1); 283 | capn_free(&ctx2); 284 | } 285 | 286 | TEST(Stream, WriteThreeSegments) { 287 | struct capn ctx1, ctx2; 288 | uint8_t buf[2048]; 289 | 290 | capn_init_malloc(&ctx1); 291 | ctx1.create = &CreateSmallSegment; 292 | struct capn_ptr root = capn_root(&ctx1); 293 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 0, 1); 294 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 295 | struct capn_ptr ptr2 = capn_new_struct(ptr1.seg, 4, 0); 296 | EXPECT_EQ(0, capn_setp(ptr1, 0, ptr2)); 297 | EXPECT_EQ(0, capn_write32(ptr2, 0, 0x12345678)); 298 | EXPECT_EQ(3, ctx1.segnum); 299 | 300 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 7*8-1, 0)); 301 | EXPECT_EQ(7*8, capn_write_mem(&ctx1, buf, 2048, 0)); 302 | 303 | EXPECT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 0)); 304 | root = capn_root(&ctx2); 305 | ptr1 = capn_getp(root, 0, 1); 306 | ptr2 = capn_getp(ptr1, 0, 1); 307 | EXPECT_EQ(0x12345678, capn_read32(ptr2, 0)); 308 | 309 | capn_free(&ctx1); 310 | capn_free(&ctx2); 311 | } 312 | 313 | TEST(Stream, WriteThreeSegmentsPacked) { 314 | struct capn ctx1, ctx2; 315 | uint8_t buf[2048]; 316 | 317 | capn_init_malloc(&ctx1); 318 | ctx1.create = &CreateSmallSegment; 319 | struct capn_ptr root = capn_root(&ctx1); 320 | struct capn_ptr ptr1 = capn_new_struct(root.seg, 0, 1); 321 | EXPECT_EQ(0, capn_setp(root, 0, ptr1)); 322 | struct capn_ptr ptr2 = capn_new_struct(ptr1.seg, 4, 0); 323 | EXPECT_EQ(0, capn_setp(ptr1, 0, ptr2)); 324 | EXPECT_EQ(0, capn_write32(ptr2, 0, 0x12345678)); 325 | EXPECT_EQ(3, ctx1.segnum); 326 | 327 | EXPECT_EQ(-1, capn_write_mem(&ctx1, buf, 20, 1)); 328 | EXPECT_EQ(21, capn_write_mem(&ctx1, buf, 2048, 1)); 329 | 330 | EXPECT_EQ(0, capn_init_mem(&ctx2, buf, 2048, 1)); 331 | root = capn_root(&ctx2); 332 | ptr1 = capn_getp(root, 0, 1); 333 | ptr2 = capn_getp(ptr1, 0, 1); 334 | EXPECT_EQ(0x12345678, capn_read32(ptr2, 0)); 335 | 336 | capn_free(&ctx1); 337 | capn_free(&ctx2); 338 | } 339 | -------------------------------------------------------------------------------- /lib/capn-malloc.c: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* capn-malloc.c 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * Copyright (C) 2014 Steve Dee 6 | * 7 | * This software may be modified and distributed under the terms 8 | * of the MIT license. See the LICENSE file for details. 9 | */ 10 | 11 | #ifdef __GNUC__ 12 | #pragma GCC diagnostic ignored "-Wunused-parameter" 13 | #endif 14 | 15 | #include "capnp_c.h" 16 | #include "capnp_priv.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /* 23 | * 8 byte alignment is required for struct capn_segment. 24 | * This struct check_segment_alignment verifies this at compile time. 25 | * 26 | * Unless capn_segment is defined with 8 byte alignment, check_segment_alignment 27 | * fails to compile in x86 mode (or on another CPU with 32-bit pointers), 28 | * as (sizeof(struct capn_segment)&7) -> (44 & 7) evaluates to 4. 29 | * It compiles in x64 mode (or on another CPU with 64-bit pointers), 30 | * as (sizeof(struct capn_segment)&7) -> (80 & 7) evaluates to 0. 31 | */ 32 | struct check_segment_alignment { 33 | unsigned int foo : (sizeof(struct capn_segment)&7) ? -1 : 1; 34 | }; 35 | 36 | static struct capn_segment *create(void *u, uint32_t id, int sz) { 37 | struct capn_segment *s; 38 | sz += sizeof(*s); 39 | if (sz < 4096) { 40 | sz = 4096; 41 | } else { 42 | sz = (sz + 4095) & ~4095; 43 | } 44 | s = (struct capn_segment*) calloc(1, sz); 45 | s->data = (char*) (s+1); 46 | s->cap = sz - sizeof(*s); 47 | s->user = s; 48 | return s; 49 | } 50 | 51 | static struct capn_segment *create_local(void *u, int sz) { 52 | return create(u, 0, sz); 53 | } 54 | 55 | void capn_init_malloc(struct capn *c) { 56 | memset(c, 0, sizeof(*c)); 57 | c->create = &create; 58 | c->create_local = &create_local; 59 | } 60 | 61 | void capn_free(struct capn *c) { 62 | struct capn_segment *s = c->seglist; 63 | while (s != NULL) { 64 | struct capn_segment *n = s->next; 65 | free(s->user); 66 | s = n; 67 | } 68 | capn_reset_copy(c); 69 | } 70 | 71 | void capn_reset_copy(struct capn *c) { 72 | struct capn_segment *s = c->copylist; 73 | while (s != NULL) { 74 | struct capn_segment *n = s->next; 75 | free(s->user); 76 | s = n; 77 | } 78 | c->copy = NULL; 79 | c->copylist = NULL; 80 | } 81 | 82 | #define ZBUF_SZ 4096 83 | 84 | static int read_fp(void *p, size_t sz, FILE *f, struct capn_stream *z, uint8_t* zbuf, int packed) { 85 | if (f && packed) { 86 | z->next_out = (uint8_t*) p; 87 | z->avail_out = sz; 88 | 89 | while (z->avail_out && capn_inflate(z) == CAPN_NEED_MORE) { 90 | int r; 91 | memmove(zbuf, z->next_in, z->avail_in); 92 | r = fread(zbuf+z->avail_in, 1, ZBUF_SZ - z->avail_in, f); 93 | if (r <= 0) 94 | return -1; 95 | z->avail_in += r; 96 | } 97 | return 0; 98 | 99 | } else if (f && !packed) { 100 | return fread(p, sz, 1, f) != 1; 101 | 102 | } else if (packed) { 103 | z->next_out = (uint8_t*) p; 104 | z->avail_out = sz; 105 | return capn_inflate(z) != 0; 106 | 107 | } else { 108 | if (z->avail_in < sz) 109 | return -1; 110 | memcpy(p, z->next_in, sz); 111 | z->next_in += sz; 112 | z->avail_in -= sz; 113 | return 0; 114 | } 115 | } 116 | 117 | static int init_fp(struct capn *c, FILE *f, struct capn_stream *z, int packed) { 118 | /* 119 | * Initialize 'c' from the contents of 'f', assuming the message has been 120 | * serialized with the standard framing format. From https://capnproto.org/encoding.html: 121 | * 122 | * When transmitting over a stream, the following should be sent. All integers are unsigned and little-endian. 123 | * (4 bytes) The number of segments, minus one (since there is always at least one segment). 124 | * (N * 4 bytes) The size of each segment, in words. 125 | * (0 or 4 bytes) Padding up to the next word boundary. 126 | * The content of each segment, in order. 127 | */ 128 | 129 | struct capn_segment *s = NULL; 130 | uint32_t i, segnum, total = 0; 131 | uint32_t hdr[1024]; 132 | uint8_t zbuf[ZBUF_SZ]; 133 | char *data = NULL; 134 | 135 | capn_init_malloc(c); 136 | 137 | /* Read the first four bytes to know how many headers we have */ 138 | if (read_fp(&segnum, 4, f, z, zbuf, packed)) 139 | goto err; 140 | 141 | segnum = capn_flip32(segnum); 142 | if (segnum > 1023) 143 | goto err; 144 | segnum++; /* The wire encoding was zero-based */ 145 | 146 | /* Read the header list */ 147 | if (read_fp(hdr, 8 * (segnum/2) + 4, f, z, zbuf, packed)) 148 | goto err; 149 | 150 | for (i = 0; i < segnum; i++) { 151 | uint32_t n = capn_flip32(hdr[i]); 152 | if (n > INT_MAX/8 || n > UINT32_MAX/8 || UINT32_MAX - total < n*8) 153 | goto err; 154 | hdr[i] = n*8; 155 | total += hdr[i]; 156 | } 157 | 158 | /* Allocate space for the data and the capn_segment structs */ 159 | s = (struct capn_segment*) calloc(1, total + (sizeof(*s) * segnum)); 160 | if (!s) 161 | goto err; 162 | 163 | /* Now read the data and setup the capn_segment structs */ 164 | data = (char*) (s+segnum); 165 | if (read_fp(data, total, f, z, zbuf, packed)) 166 | goto err; 167 | 168 | for (i = 0; i < segnum; i++) { 169 | s[i].len = s[i].cap = hdr[i]; 170 | s[i].data = data; 171 | data += s[i].len; 172 | capn_append_segment(c, &s[i]); 173 | } 174 | 175 | /* Set the entire region to be freed on the last segment */ 176 | s[segnum-1].user = s; 177 | 178 | return 0; 179 | 180 | err: 181 | memset(c, 0, sizeof(*c)); 182 | free(s); 183 | return -1; 184 | } 185 | 186 | int capn_init_fp(struct capn *c, FILE *f, int packed) { 187 | struct capn_stream z; 188 | memset(&z, 0, sizeof(z)); 189 | return init_fp(c, f, &z, packed); 190 | } 191 | 192 | int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed) { 193 | struct capn_stream z; 194 | memset(&z, 0, sizeof(z)); 195 | z.next_in = p; 196 | z.avail_in = sz; 197 | return init_fp(c, NULL, &z, packed); 198 | } 199 | 200 | static void header_calc(struct capn *c, uint32_t *headerlen, size_t *headersz) 201 | { 202 | /* segnum == 1: 203 | * [segnum][segsiz] 204 | * segnum == 2: 205 | * [segnum][segsiz][segsiz][zeroes] 206 | * segnum == 3: 207 | * [segnum][segsiz][segsiz][segsiz] 208 | * segnum == 4: 209 | * [segnum][segsiz][segsiz][segsiz][segsiz][zeroes] 210 | */ 211 | *headerlen = ((2 + c->segnum) / 2) * 2; 212 | *headersz = 4 * *headerlen; 213 | } 214 | 215 | static int header_render(struct capn *c, struct capn_segment *seg, uint32_t *header, uint32_t headerlen, size_t *datasz) 216 | { 217 | size_t i; 218 | 219 | header[0] = capn_flip32(c->segnum - 1); 220 | header[headerlen-1] = 0; /* Zero out the spare position in the header sizes */ 221 | for (i = 0; i < c->segnum; i++, seg = seg->next) { 222 | if (0 == seg) 223 | return -1; 224 | *datasz += seg->len; 225 | header[1 + i] = capn_flip32(seg->len / 8); 226 | } 227 | if (0 != seg) 228 | return -1; 229 | 230 | return 0; 231 | } 232 | 233 | static int64_t capn_write_mem_packed(struct capn *c, uint8_t *p, size_t sz) 234 | { 235 | struct capn_segment *seg; 236 | struct capn_ptr root; 237 | uint32_t headerlen; 238 | size_t headersz, datasz = 0; 239 | uint32_t *header; 240 | struct capn_stream z; 241 | int ret; 242 | 243 | root = capn_root(c); 244 | header_calc(c, &headerlen, &headersz); 245 | header = (uint32_t*) (p + headersz + 2); /* must reserve two bytes for worst case expansion */ 246 | 247 | if (sz < headersz*2 + 2) /* We must have space for temporary writing of header to deflate */ 248 | return -1; 249 | 250 | ret = header_render(c, root.seg, header, headerlen, &datasz); 251 | if (ret != 0) 252 | return -1; 253 | 254 | memset(&z, 0, sizeof(z)); 255 | z.next_in = (uint8_t *)header; 256 | z.avail_in = headersz; 257 | z.next_out = p; 258 | z.avail_out = sz; 259 | 260 | // pack the headers 261 | ret = capn_deflate(&z); 262 | if (ret != 0 || z.avail_in != 0) 263 | return -1; 264 | 265 | for (seg = root.seg; seg; seg = seg->next) { 266 | z.next_in = (uint8_t *)seg->data; 267 | z.avail_in = seg->len; 268 | ret = capn_deflate(&z); 269 | if (ret != 0 || z.avail_in != 0) 270 | return -1; 271 | } 272 | 273 | return (int64_t)(sz - z.avail_out); 274 | } 275 | 276 | int64_t 277 | capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed) 278 | { 279 | struct capn_segment *seg; 280 | struct capn_ptr root; 281 | uint32_t headerlen; 282 | size_t headersz, datasz = 0; 283 | uint32_t *header; 284 | int ret; 285 | 286 | if (c->segnum == 0) 287 | return -1; 288 | 289 | if (packed) 290 | return capn_write_mem_packed(c, p, sz); 291 | 292 | root = capn_root(c); 293 | header_calc(c, &headerlen, &headersz); 294 | header = (uint32_t*) p; 295 | 296 | if (sz < headersz) 297 | return -1; 298 | 299 | ret = header_render(c, root.seg, header, headerlen, &datasz); 300 | if (ret != 0) 301 | return -1; 302 | 303 | if (sz < headersz + datasz) 304 | return -1; 305 | 306 | p += headersz; 307 | 308 | for (seg = root.seg; seg; seg = seg->next) { 309 | memcpy(p, seg->data, seg->len); 310 | p += seg->len; 311 | } 312 | 313 | return (int64_t)(headersz + datasz); 314 | } 315 | 316 | static int _write_fd(ssize_t (*write_fd)(int fd, const void *p, size_t count), int fd, void *p, size_t count) 317 | { 318 | ssize_t ret; 319 | size_t sent = 0; 320 | 321 | while (sent < count) { 322 | ret = write_fd(fd, ((uint8_t*)p)+sent, count-sent); 323 | if (ret < 0) { 324 | if (errno == EAGAIN || errno == EINTR) 325 | continue; 326 | else 327 | return -1; 328 | } 329 | sent += ret; 330 | } 331 | 332 | return 0; 333 | } 334 | 335 | int capn_write_fd(struct capn *c, ssize_t (*write_fd)(int fd, const void *p, size_t count), int fd, int packed) 336 | { 337 | unsigned char buf[4096]; 338 | struct capn_segment *seg; 339 | struct capn_ptr root; 340 | uint32_t headerlen; 341 | size_t headersz, datasz = 0; 342 | int ret; 343 | struct capn_stream z; 344 | unsigned char *p; 345 | 346 | if (c->segnum == 0) 347 | return -1; 348 | 349 | root = capn_root(c); 350 | header_calc(c, &headerlen, &headersz); 351 | 352 | if (sizeof(buf) < headersz) 353 | return -1; 354 | 355 | ret = header_render(c, root.seg, (uint32_t*)buf, headerlen, &datasz); 356 | if (ret != 0) 357 | return -1; 358 | 359 | if (packed) { 360 | const int headerrem = sizeof(buf) - headersz; 361 | const int maxpack = headersz + 2; 362 | if (headerrem < maxpack) 363 | return -1; 364 | 365 | memset(&z, 0, sizeof(z)); 366 | z.next_in = buf; 367 | z.avail_in = headersz; 368 | z.next_out = buf + headersz; 369 | z.avail_out = headerrem; 370 | ret = capn_deflate(&z); 371 | if (ret != 0) 372 | return -1; 373 | 374 | p = buf + headersz; 375 | headersz = headerrem - z.avail_out; 376 | } else { 377 | p = buf; 378 | } 379 | 380 | ret = _write_fd(write_fd, fd, p, headersz); 381 | if (ret < 0) 382 | return -1; 383 | 384 | datasz = headersz; 385 | for (seg = root.seg; seg; seg = seg->next) { 386 | size_t bufsz; 387 | if (packed) { 388 | memset(&z, 0, sizeof(z)); 389 | z.next_in = (uint8_t*)seg->data; 390 | z.avail_in = seg->len; 391 | z.next_out = buf; 392 | z.avail_out = sizeof(buf); 393 | ret = capn_deflate(&z); 394 | if (ret != 0) 395 | return -1; 396 | p = buf; 397 | bufsz = sizeof(buf) - z.avail_out; 398 | } else { 399 | p = (uint8_t*)seg->data; 400 | bufsz = seg->len; 401 | } 402 | ret = _write_fd(write_fd, fd, p, bufsz); 403 | if (ret < 0) 404 | return -1; 405 | datasz += bufsz; 406 | } 407 | 408 | return datasz; 409 | } 410 | 411 | int64_t capn_size(struct capn *c) 412 | { 413 | size_t headersz, datasz = 0; 414 | struct capn_ptr root; 415 | struct capn_segment *seg; 416 | uint32_t i; 417 | 418 | if (c->segnum == 0) 419 | return -1; 420 | 421 | root = capn_root(c); 422 | seg = root.seg; 423 | 424 | headersz = 8 * ((2 + c->segnum) / 2); 425 | 426 | for (i = 0; i < c->segnum; i++, seg = seg->next) { 427 | if (0 == seg) 428 | return -1; 429 | datasz += seg->len; 430 | } 431 | if (0 != seg) 432 | return -1; 433 | 434 | return (int64_t)(headersz + datasz); 435 | } 436 | -------------------------------------------------------------------------------- /lib/capnp_c.h: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* capnp_c.h 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * Copyright (C) 2014 Steve Dee 6 | * 7 | * This software may be modified and distributed under the terms 8 | * of the MIT license. See the LICENSE file for details. 9 | */ 10 | 11 | #ifndef CAPNP_C_H 12 | #define CAPNP_C_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #if defined(unix) && !defined(__APPLE__) && !defined(__FreeBSD__) 19 | #include 20 | #elif defined(__FreeBSD__) 21 | #include 22 | #endif 23 | 24 | /* ssize_t is a POSIX type, not an ISO C one... 25 | * Windows seems to only have SSIZE_T in BaseTsd.h 26 | */ 27 | #ifdef _MSC_VER 28 | typedef intmax_t ssize_t; 29 | #else 30 | #include 31 | #endif 32 | 33 | // Cross-platform macro ALIGNED_(x) aligns a struct by `x` bytes. 34 | #ifdef _MSC_VER 35 | #define ALIGNED_(x) __declspec(align(x)) 36 | #endif 37 | #ifdef __GNUC__ 38 | #define ALIGNED_(x) __attribute__ ((aligned(x))) 39 | #endif 40 | 41 | #ifdef __cplusplus 42 | extern "C" { 43 | #endif 44 | 45 | #if defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) 46 | #define CAPN_INLINE static inline 47 | #else 48 | #define CAPN_INLINE static 49 | #endif 50 | 51 | #define CAPN_VERSION 1 52 | 53 | /* struct capn is a common structure shared between segments in the same 54 | * session/context so that far pointers between segments will be created. 55 | * 56 | * lookup is used to lookup segments by id when derefencing a far pointer 57 | * 58 | * create is used to create or lookup an alternate segment that has at least 59 | * sz available (ie returned seg->len + sz <= seg->cap) 60 | * 61 | * create_local is used to create a segment for the copy tree and should be 62 | * allocated in the local memory space. 63 | * 64 | * Allocated segments must be zero initialized. 65 | * 66 | * create and lookup can be NULL if you don't need multiple segments and don't 67 | * want to support copying 68 | * 69 | * seglist and copylist are linked lists which can be used to free up segments 70 | * on cleanup, but should not be modified by the user. 71 | * 72 | * lookup, create, create_local, and user can be set by the user. Other values 73 | * should be zero initialized. 74 | */ 75 | struct capn { 76 | /* user settable */ 77 | struct capn_segment *(*lookup)(void* /*user*/, uint32_t /*id */); 78 | struct capn_segment *(*create)(void* /*user*/, uint32_t /*id */, int /*sz*/); 79 | struct capn_segment *(*create_local)(void* /*user*/, int /*sz*/); 80 | void *user; 81 | /* zero initialized, user should not modify */ 82 | uint32_t segnum; 83 | struct capn_tree *copy; 84 | struct capn_tree *segtree; 85 | struct capn_segment *seglist, *lastseg; 86 | struct capn_segment *copylist; 87 | }; 88 | 89 | /* struct capn_tree is a rb tree header used internally for the segment id 90 | * lookup and copy tree */ 91 | struct capn_tree { 92 | struct capn_tree *parent, *link[2]; 93 | unsigned int red : 1; 94 | }; 95 | 96 | struct capn_tree *capn_tree_insert(struct capn_tree *root, struct capn_tree *n); 97 | 98 | /* struct capn_segment contains the information about a single segment. 99 | * 100 | * capn points to a struct capn that is shared between segments in the 101 | * same session 102 | * 103 | * id specifies the segment id, used for far pointers 104 | * 105 | * data specifies the segment data. This should not move after creation. 106 | * 107 | * len specifies the current segment length. This is 0 for a blank 108 | * segment. 109 | * 110 | * cap specifies the segment capacity. 111 | * 112 | * When creating new structures len will be incremented until it reaches cap, 113 | * at which point a new segment will be requested via capn->create. The 114 | * create callback can either create a new segment or expand an existing 115 | * one by incrementing cap and returning the expanded segment. 116 | * 117 | * data, len, and cap must all be 8 byte aligned, hence the ALIGNED_(8) macro 118 | * on the struct definition. 119 | * 120 | * data, len, cap, and user should all be set by the user. Other values 121 | * should be zero initialized. 122 | */ 123 | 124 | struct ALIGNED_(8) capn_segment { 125 | struct capn_tree hdr; 126 | struct capn_segment *next; 127 | struct capn *capn; 128 | uint32_t id; 129 | /* user settable */ 130 | char *data; 131 | size_t len, cap; 132 | void *user; 133 | }; 134 | 135 | enum CAPN_TYPE { 136 | CAPN_NULL = 0, 137 | CAPN_STRUCT = 1, 138 | CAPN_LIST = 2, 139 | CAPN_PTR_LIST = 3, 140 | CAPN_BIT_LIST = 4, 141 | CAPN_FAR_POINTER = 5, 142 | }; 143 | 144 | struct capn_ptr { 145 | unsigned int type : 4; 146 | unsigned int has_ptr_tag : 1; 147 | unsigned int is_list_member : 1; 148 | unsigned int is_composite_list : 1; 149 | unsigned int datasz : 19; 150 | unsigned int ptrs : 16; 151 | int len; 152 | char *data; 153 | struct capn_segment *seg; 154 | }; 155 | 156 | struct capn_text { 157 | int len; 158 | const char *str; 159 | struct capn_segment *seg; 160 | }; 161 | 162 | typedef struct capn_ptr capn_ptr; 163 | typedef struct capn_text capn_text; 164 | typedef struct {capn_ptr p;} capn_data; 165 | typedef struct {capn_ptr p;} capn_list1; 166 | typedef struct {capn_ptr p;} capn_list8; 167 | typedef struct {capn_ptr p;} capn_list16; 168 | typedef struct {capn_ptr p;} capn_list32; 169 | typedef struct {capn_ptr p;} capn_list64; 170 | 171 | struct capn_msg { 172 | struct capn_segment *seg; 173 | uint64_t iface; 174 | uint16_t method; 175 | capn_ptr args; 176 | }; 177 | 178 | /* capn_append_segment appends a segment to a session */ 179 | void capn_append_segment(struct capn*, struct capn_segment*); 180 | 181 | capn_ptr capn_root(struct capn *c); 182 | void capn_resolve(capn_ptr *p); 183 | 184 | #define capn_len(list) ((list).p.type == CAPN_FAR_POINTER ? (capn_resolve(&(list).p), (list).p.len) : (list).p.len) 185 | 186 | /* capn_getp|setp functions get/set ptrs in list/structs 187 | * off is the list index or pointer index in a struct 188 | * capn_setp will copy the data, create far pointers, etc if the target 189 | * is in a different segment/context. 190 | * Both of these will use/return inner pointers for composite lists. 191 | */ 192 | capn_ptr capn_getp(capn_ptr p, int off, int resolve); 193 | int capn_setp(capn_ptr p, int off, capn_ptr tgt); 194 | 195 | capn_text capn_get_text(capn_ptr p, int off, capn_text def); 196 | capn_data capn_get_data(capn_ptr p, int off); 197 | int capn_set_text(capn_ptr p, int off, capn_text tgt); 198 | /* there is no set_data -- use capn_new_list8 + capn_setv8 instead 199 | * and set data.p = list.p */ 200 | 201 | /* capn_get* functions get data from a list 202 | * The length of the list is given by p->size 203 | * off specifies how far into the list to start 204 | * sz indicates the number of elements to get 205 | * The function returns the number of elements read or -1 on an error. 206 | * off must be byte aligned for capn_getv1 207 | */ 208 | int capn_get1(capn_list1 p, int off); 209 | uint8_t capn_get8(capn_list8 p, int off); 210 | uint16_t capn_get16(capn_list16 p, int off); 211 | uint32_t capn_get32(capn_list32 p, int off); 212 | uint64_t capn_get64(capn_list64 p, int off); 213 | int capn_getv1(capn_list1 p, int off, uint8_t *data, int sz); 214 | int capn_getv8(capn_list8 p, int off, uint8_t *data, int sz); 215 | int capn_getv16(capn_list16 p, int off, uint16_t *data, int sz); 216 | int capn_getv32(capn_list32 p, int off, uint32_t *data, int sz); 217 | int capn_getv64(capn_list64 p, int off, uint64_t *data, int sz); 218 | 219 | /* capn_set* functions set data in a list 220 | * off specifies how far into the list to start 221 | * sz indicates the number of elements to write 222 | * The function returns the number of elemnts written or -1 on an error. 223 | * off must be byte aligned for capn_setv1 224 | */ 225 | int capn_set1(capn_list1 p, int off, int v); 226 | int capn_set8(capn_list8 p, int off, uint8_t v); 227 | int capn_set16(capn_list16 p, int off, uint16_t v); 228 | int capn_set32(capn_list32 p, int off, uint32_t v); 229 | int capn_set64(capn_list64 p, int off, uint64_t v); 230 | int capn_setv1(capn_list1 p, int off, const uint8_t *data, int sz); 231 | int capn_setv8(capn_list8 p, int off, const uint8_t *data, int sz); 232 | int capn_setv16(capn_list16 p, int off, const uint16_t *data, int sz); 233 | int capn_setv32(capn_list32 p, int off, const uint32_t *data, int sz); 234 | int capn_setv64(capn_list64 p, int off, const uint64_t *data, int sz); 235 | 236 | /* capn_new_* functions create a new object 237 | * datasz is in bytes, ptrs is # of pointers, sz is # of elements in the list 238 | * On an error a CAPN_NULL pointer is returned 239 | */ 240 | capn_ptr capn_new_string(struct capn_segment *seg, const char *str, ssize_t sz); 241 | capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs); 242 | capn_ptr capn_new_interface(struct capn_segment *seg, int datasz, int ptrs); 243 | capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz); 244 | capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs); 245 | capn_list1 capn_new_list1(struct capn_segment *seg, int sz); 246 | capn_list8 capn_new_list8(struct capn_segment *seg, int sz); 247 | capn_list16 capn_new_list16(struct capn_segment *seg, int sz); 248 | capn_list32 capn_new_list32(struct capn_segment *seg, int sz); 249 | capn_list64 capn_new_list64(struct capn_segment *seg, int sz); 250 | 251 | /* capn_read|write* functions read/write struct values 252 | * off is the offset into the structure in bytes 253 | * Rarely should these be called directly, instead use the generated code. 254 | * Data must be xored with the default value 255 | * These are inlined 256 | */ 257 | CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off); 258 | CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off); 259 | CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off); 260 | CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off); 261 | CAPN_INLINE int capn_write1(capn_ptr p, int off, int val); 262 | CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val); 263 | CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val); 264 | CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val); 265 | CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val); 266 | 267 | /* capn_init_malloc inits the capn struct with a create function which 268 | * allocates segments on the heap using malloc 269 | * 270 | * capn_init_(fp|mem) inits by reading segments in from the file/memory buffer 271 | * in serialized form (optionally packed). It will then setup the create 272 | * function ala capn_init_malloc so that further segments can be created. 273 | * 274 | * capn_free frees all the segment headers and data created by the create 275 | * function setup by capn_init_* 276 | */ 277 | void capn_init_malloc(struct capn *c); 278 | int capn_init_fp(struct capn *c, FILE *f, int packed); 279 | int capn_init_mem(struct capn *c, const uint8_t *p, size_t sz, int packed); 280 | 281 | /* capn_size() calculates the amount of memory required to serialise the given 282 | * Cap'n Proto structure in the unpacked format. It does NOT apply to packed 283 | * serialisation, as that may (in rare cases) actually become bigger than the 284 | * input. A buffer of this size can then be passed to capn_write_mem() without 285 | * fear of truncation (again, only in the unpacked case). 286 | */ 287 | int64_t capn_size(struct capn *c); 288 | 289 | /* capn_write_(fp|mem) writes segments to the file/memory buffer in 290 | * serialized form and returns the number of bytes written. 291 | */ 292 | /* TODO */ 293 | /*int capn_write_fp(struct capn *c, FILE *f, int packed);*/ 294 | int capn_write_fd(struct capn *c, ssize_t (*write_fd)(int fd, const void *p, size_t count), int fd, int packed); 295 | int64_t capn_write_mem(struct capn *c, uint8_t *p, size_t sz, int packed); 296 | 297 | void capn_free(struct capn *c); 298 | void capn_reset_copy(struct capn *c); 299 | 300 | /* Inline functions */ 301 | 302 | 303 | CAPN_INLINE uint8_t capn_flip8(uint8_t v) { 304 | return v; 305 | } 306 | CAPN_INLINE uint16_t capn_flip16(uint16_t v) { 307 | #if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN) 308 | return v; 309 | #elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \ 310 | defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 311 | return __builtin_bswap16(v); 312 | #else 313 | union { uint16_t u; uint8_t v[2]; } s; 314 | s.v[0] = (uint8_t)v; 315 | s.v[1] = (uint8_t)(v>>8); 316 | return s.u; 317 | #endif 318 | } 319 | CAPN_INLINE uint32_t capn_flip32(uint32_t v) { 320 | #if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN) 321 | return v; 322 | #elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \ 323 | defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 324 | return __builtin_bswap32(v); 325 | #else 326 | union { uint32_t u; uint8_t v[4]; } s; 327 | s.v[0] = (uint8_t)v; 328 | s.v[1] = (uint8_t)(v>>8); 329 | s.v[2] = (uint8_t)(v>>16); 330 | s.v[3] = (uint8_t)(v>>24); 331 | return s.u; 332 | #endif 333 | } 334 | CAPN_INLINE uint64_t capn_flip64(uint64_t v) { 335 | #if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN) 336 | return v; 337 | #elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN) && \ 338 | defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8 339 | return __builtin_bswap64(v); 340 | #else 341 | union { uint64_t u; uint8_t v[8]; } s; 342 | s.v[0] = (uint8_t)v; 343 | s.v[1] = (uint8_t)(v>>8); 344 | s.v[2] = (uint8_t)(v>>16); 345 | s.v[3] = (uint8_t)(v>>24); 346 | s.v[4] = (uint8_t)(v>>32); 347 | s.v[5] = (uint8_t)(v>>40); 348 | s.v[6] = (uint8_t)(v>>48); 349 | s.v[7] = (uint8_t)(v>>56); 350 | return s.u; 351 | #endif 352 | } 353 | 354 | CAPN_INLINE int capn_write1(capn_ptr p, int off, int val) { 355 | if (off >= p.datasz*8) { 356 | return -1; 357 | } else if (val) { 358 | uint8_t tmp = (uint8_t)(1 << (off & 7)); 359 | ((uint8_t*) p.data)[off >> 3] |= tmp; 360 | return 0; 361 | } else { 362 | uint8_t tmp = (uint8_t)(~(1 << (off & 7))); 363 | ((uint8_t*) p.data)[off >> 3] &= tmp; 364 | return 0; 365 | } 366 | } 367 | 368 | CAPN_INLINE uint8_t capn_read8(capn_ptr p, int off) { 369 | return off+1 <= p.datasz ? capn_flip8(*(uint8_t*) (p.data+off)) : 0; 370 | } 371 | CAPN_INLINE int capn_write8(capn_ptr p, int off, uint8_t val) { 372 | if (off+1 <= p.datasz) { 373 | *(uint8_t*) (p.data+off) = capn_flip8(val); 374 | return 0; 375 | } else { 376 | return -1; 377 | } 378 | } 379 | 380 | CAPN_INLINE uint16_t capn_read16(capn_ptr p, int off) { 381 | return off+2 <= p.datasz ? capn_flip16(*(uint16_t*) (p.data+off)) : 0; 382 | } 383 | CAPN_INLINE int capn_write16(capn_ptr p, int off, uint16_t val) { 384 | if (off+2 <= p.datasz) { 385 | *(uint16_t*) (p.data+off) = capn_flip16(val); 386 | return 0; 387 | } else { 388 | return -1; 389 | } 390 | } 391 | 392 | CAPN_INLINE uint32_t capn_read32(capn_ptr p, int off) { 393 | return off+4 <= p.datasz ? capn_flip32(*(uint32_t*) (p.data+off)) : 0; 394 | } 395 | CAPN_INLINE int capn_write32(capn_ptr p, int off, uint32_t val) { 396 | if (off+4 <= p.datasz) { 397 | *(uint32_t*) (p.data+off) = capn_flip32(val); 398 | return 0; 399 | } else { 400 | return -1; 401 | } 402 | } 403 | 404 | CAPN_INLINE uint64_t capn_read64(capn_ptr p, int off) { 405 | return off+8 <= p.datasz ? capn_flip64(*(uint64_t*) (p.data+off)) : 0; 406 | } 407 | CAPN_INLINE int capn_write64(capn_ptr p, int off, uint64_t val) { 408 | if (off+8 <= p.datasz) { 409 | *(uint64_t*) (p.data+off) = capn_flip64(val); 410 | return 0; 411 | } else { 412 | return -1; 413 | } 414 | } 415 | 416 | union capn_conv_f32 { 417 | uint32_t u; 418 | float f; 419 | }; 420 | 421 | union capn_conv_f64 { 422 | uint64_t u; 423 | double f; 424 | }; 425 | 426 | CAPN_INLINE float capn_to_f32(uint32_t v) { 427 | union capn_conv_f32 u; 428 | u.u = v; 429 | return u.f; 430 | } 431 | CAPN_INLINE double capn_to_f64(uint64_t v) { 432 | union capn_conv_f64 u; 433 | u.u = v; 434 | return u.f; 435 | } 436 | CAPN_INLINE uint32_t capn_from_f32(float v) { 437 | union capn_conv_f32 u; 438 | u.f = v; 439 | return u.u; 440 | } 441 | CAPN_INLINE uint64_t capn_from_f64(double v) { 442 | union capn_conv_f64 u; 443 | u.f = v; 444 | return u.u; 445 | } 446 | 447 | #ifdef __cplusplus 448 | } 449 | #endif 450 | 451 | #endif 452 | -------------------------------------------------------------------------------- /tests/capn-test.cpp: -------------------------------------------------------------------------------- 1 | /* capn-test.cpp 2 | * 3 | * Copyright (C) 2013 James McKaskill 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | static int g_AddTag = 1; 13 | #define ADD_TAG g_AddTag 14 | 15 | #include "capn.c" 16 | #include "capn-malloc.c" 17 | 18 | template 19 | union AlignedData { 20 | uint8_t bytes[wordCount * 8]; 21 | uint64_t words[wordCount]; 22 | }; 23 | 24 | class Session { 25 | public: 26 | Session() {capn_init_malloc(&capn);} 27 | ~Session() {capn_free(&capn);} 28 | struct capn capn; 29 | }; 30 | 31 | 32 | 33 | 34 | 35 | TEST(WireFormat, SimpleRawDataStruct) { 36 | AlignedData<2> data = {{ 37 | // Struct ref, offset = 1, dataSize = 1, referenceCount = 0 38 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 39 | // Content for the data segment. 40 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 41 | }}; 42 | 43 | struct capn_segment seg; 44 | memset(&seg, 0, sizeof(seg)); 45 | seg.data = (char*) data.bytes; 46 | seg.len = seg.cap = sizeof(data.bytes); 47 | 48 | struct capn ctx; 49 | memset(&ctx, 0, sizeof(ctx)); 50 | capn_append_segment(&ctx, &seg); 51 | 52 | EXPECT_EQ(&seg, ctx.seglist); 53 | EXPECT_EQ(&seg, ctx.lastseg); 54 | EXPECT_EQ(&seg.hdr, ctx.segtree); 55 | EXPECT_EQ(1, ctx.segnum); 56 | EXPECT_EQ(0, seg.id); 57 | 58 | struct capn_ptr ptr = capn_getp(capn_root(&ctx), 0, 1); 59 | EXPECT_EQ(CAPN_STRUCT, ptr.type); 60 | EXPECT_EQ(8, ptr.datasz); 61 | EXPECT_EQ(0, ptr.ptrs); 62 | 63 | EXPECT_EQ(UINT64_C(0xefcdab8967452301), capn_read64(ptr, 0)); 64 | EXPECT_EQ(UINT64_C(0), capn_read64(ptr, 8)); 65 | EXPECT_EQ(UINT32_C(0x67452301), capn_read32(ptr, 0)); 66 | EXPECT_EQ(UINT32_C(0xefcdab89), capn_read32(ptr, 4)); 67 | EXPECT_EQ(UINT32_C(0), capn_read32(ptr, 8)); 68 | EXPECT_EQ(UINT16_C(0x2301), capn_read16(ptr, 0)); 69 | EXPECT_EQ(UINT16_C(0x6745), capn_read16(ptr, 2)); 70 | EXPECT_EQ(UINT16_C(0xab89), capn_read16(ptr, 4)); 71 | EXPECT_EQ(UINT16_C(0xefcd), capn_read16(ptr, 6)); 72 | EXPECT_EQ(UINT16_C(0), capn_read16(ptr, 8)); 73 | } 74 | 75 | static void setupStruct(struct capn *ctx) { 76 | struct capn_ptr root = capn_root(ctx); 77 | ASSERT_EQ(CAPN_PTR_LIST, root.type); 78 | ASSERT_EQ(1, root.len); 79 | 80 | struct capn_ptr ptr = capn_new_struct(root.seg, 16, 6); 81 | ASSERT_EQ(CAPN_STRUCT, ptr.type); 82 | EXPECT_EQ(16, ptr.datasz); 83 | EXPECT_EQ(6, ptr.ptrs); 84 | EXPECT_EQ(0, capn_setp(root, 0, ptr)); 85 | 86 | EXPECT_EQ(0, capn_write64(ptr, 0, UINT64_C(0x1011121314151617))); 87 | EXPECT_EQ(0, capn_write32(ptr, 8, UINT32_C(0x20212223))); 88 | EXPECT_EQ(0, capn_write16(ptr, 12, UINT16_C(0x3031))); 89 | EXPECT_EQ(0, capn_write8(ptr, 14, 0x40)); 90 | EXPECT_EQ(0, capn_write8(ptr, 15, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2))); 91 | 92 | capn_ptr subStruct = capn_new_struct(ptr.seg, 8, 0); 93 | ASSERT_EQ(CAPN_STRUCT, subStruct.type); 94 | EXPECT_EQ(8, subStruct.datasz); 95 | EXPECT_EQ(0, subStruct.ptrs); 96 | EXPECT_EQ(0, capn_write32(subStruct, 0, 123)); 97 | EXPECT_NE(0, capn_write32(subStruct, 8, 124)); 98 | EXPECT_EQ(0, capn_setp(ptr, 0, subStruct)); 99 | 100 | capn_list32 list32 = capn_new_list32(ptr.seg, 3); 101 | capn_list64 list64 = {list32.p}; 102 | ASSERT_EQ(CAPN_LIST, list32.p.type); 103 | EXPECT_EQ(3, list32.p.len); 104 | EXPECT_EQ(4, list32.p.datasz); 105 | EXPECT_EQ(0, capn_set32(list32, 0, 200)); 106 | EXPECT_EQ(0, capn_set32(list32, 1, 201)); 107 | EXPECT_EQ(0, capn_set32(list32, 2, 202)); 108 | EXPECT_NE(0, capn_set32(list32, 3, 203)); 109 | EXPECT_NE(0, capn_set64(list64, 0, 405)); 110 | EXPECT_EQ(0, capn_setp(ptr, 1, list32.p)); 111 | 112 | capn_ptr list = capn_new_list(ptr.seg, 4, 4, 1); 113 | ASSERT_EQ(CAPN_LIST, list.type); 114 | ASSERT_EQ(1, list.is_composite_list); 115 | EXPECT_EQ(4, list.len); 116 | EXPECT_EQ(8, list.datasz); 117 | EXPECT_EQ(1, list.ptrs); 118 | EXPECT_EQ(0, capn_setp(ptr, 2, list)); 119 | for (int i = 0; i < 4; i++) { 120 | capn_ptr element = capn_getp(list, i, 1); 121 | ASSERT_EQ(CAPN_STRUCT, element.type); 122 | EXPECT_EQ(1, element.is_list_member); 123 | EXPECT_EQ(8, element.datasz); 124 | EXPECT_EQ(1, element.ptrs); 125 | EXPECT_EQ(0, capn_write32(element, 0, 300+i)); 126 | 127 | capn_ptr subelement = capn_new_struct(element.seg, 8, 0); 128 | ASSERT_EQ(CAPN_STRUCT, subelement.type); 129 | EXPECT_EQ(8, subelement.datasz); 130 | EXPECT_EQ(0, subelement.ptrs); 131 | EXPECT_EQ(0, capn_write32(subelement, 0, 400+i)); 132 | EXPECT_EQ(0, capn_setp(element, 0, subelement)); 133 | } 134 | 135 | list = capn_new_ptr_list(ptr.seg, 5); 136 | ASSERT_EQ(CAPN_PTR_LIST, list.type); 137 | EXPECT_EQ(5, list.len); 138 | EXPECT_EQ(0, capn_setp(ptr, 3, list)); 139 | for (int i = 0; i < 5; i++) { 140 | capn_list16 element = capn_new_list16(list.seg, i+1); 141 | ASSERT_EQ(CAPN_LIST, element.p.type); 142 | EXPECT_EQ(i+1, element.p.len); 143 | EXPECT_EQ(2, element.p.datasz); 144 | EXPECT_EQ(0, element.p.ptrs); 145 | EXPECT_EQ(0, capn_setp(list, i, element.p)); 146 | for (int j = 0; j <= i; j++) { 147 | EXPECT_EQ(0, capn_set16(element, j, 500+j)); 148 | } 149 | } 150 | 151 | capn_ptr recurse = capn_new_struct(ptr.seg, 0, 2); 152 | EXPECT_EQ(CAPN_STRUCT, recurse.type); 153 | EXPECT_EQ(0, recurse.datasz); 154 | EXPECT_EQ(2, recurse.ptrs); 155 | EXPECT_EQ(0, capn_setp(recurse, 0, recurse)); 156 | EXPECT_EQ(0, capn_setp(ptr, 4, recurse)); 157 | 158 | } 159 | 160 | static void checkStruct(struct capn *ctx) { 161 | capn_ptr ptr = capn_getp(capn_root(ctx), 0, 1); 162 | EXPECT_EQ(CAPN_STRUCT, ptr.type); 163 | EXPECT_EQ(16, ptr.datasz); 164 | EXPECT_EQ(6, ptr.ptrs); 165 | EXPECT_EQ(UINT64_C(0x1011121314151617), capn_read64(ptr, 0)); 166 | EXPECT_EQ(UINT32_C(0x20212223), capn_read32(ptr, 8)); 167 | EXPECT_EQ(0x3031, capn_read16(ptr, 12)); 168 | EXPECT_EQ(0x40, capn_read8(ptr, 14)); 169 | EXPECT_EQ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 2), capn_read8(ptr, 15)); 170 | 171 | capn_ptr subStruct = capn_getp(ptr, 0, 1); 172 | EXPECT_EQ(CAPN_STRUCT, subStruct.type); 173 | EXPECT_EQ(8, subStruct.datasz); 174 | EXPECT_EQ(0, subStruct.ptrs); 175 | EXPECT_EQ(123, capn_read32(subStruct, 0)); 176 | 177 | capn_list32 list32 = {capn_getp(ptr, 1, 1)}; 178 | capn_list8 list8 = {list32.p}; 179 | capn_list16 list16 = {list32.p}; 180 | capn_list64 list64 = {list32.p}; 181 | EXPECT_EQ(CAPN_LIST, list32.p.type); 182 | EXPECT_EQ(3, list32.p.len); 183 | EXPECT_EQ(4, list32.p.datasz); 184 | EXPECT_EQ(0, list32.p.ptrs); 185 | EXPECT_EQ(200, capn_get32(list32, 0)); 186 | EXPECT_EQ(201, capn_get32(list32, 1)); 187 | EXPECT_EQ(202, capn_get32(list32, 2)); 188 | EXPECT_EQ(0, capn_get32(list32, 3)); 189 | EXPECT_EQ(0, capn_get64(list64, 0)); 190 | EXPECT_EQ(201, capn_get8(list8, 1)); 191 | EXPECT_EQ(202, capn_get16(list16, 2)); 192 | 193 | capn_ptr list = capn_getp(ptr, 2, 1); 194 | EXPECT_EQ(CAPN_LIST, list.type); 195 | EXPECT_EQ(1, list.is_composite_list); 196 | EXPECT_EQ(4, list.len); 197 | EXPECT_EQ(8, list.datasz); 198 | EXPECT_EQ(1, list.ptrs); 199 | 200 | for (int i = 0; i < 4; i++) { 201 | capn_ptr element = capn_getp(list, i, 1); 202 | EXPECT_EQ(CAPN_STRUCT, element.type); 203 | EXPECT_EQ(1, element.is_list_member); 204 | EXPECT_EQ(8, element.datasz); 205 | EXPECT_EQ(1, element.ptrs); 206 | EXPECT_EQ(300+i, capn_read32(element,0)); 207 | 208 | capn_ptr subelement = capn_getp(element, 0, 1); 209 | EXPECT_EQ(CAPN_STRUCT, subelement.type); 210 | EXPECT_EQ(8, subelement.datasz); 211 | EXPECT_EQ(0, subelement.ptrs); 212 | EXPECT_EQ(400+i, capn_read32(subelement, 0)); 213 | } 214 | 215 | list = capn_getp(ptr, 3, 1); 216 | EXPECT_EQ(CAPN_PTR_LIST, list.type); 217 | EXPECT_EQ(5, list.len); 218 | for (int i = 0; i < 5; i++) { 219 | capn_list16 element = {capn_getp(list, i, 1)}; 220 | EXPECT_EQ(CAPN_LIST, element.p.type); 221 | EXPECT_EQ(i+1, element.p.len); 222 | EXPECT_EQ(2, element.p.datasz); 223 | EXPECT_EQ(0, element.p.ptrs); 224 | for (int j = 0; j <= i; j++) { 225 | EXPECT_EQ(500+j, capn_get16(element, j)); 226 | } 227 | } 228 | 229 | capn_ptr recurse = capn_getp(ptr, 4, 1); 230 | EXPECT_EQ(CAPN_STRUCT, recurse.type); 231 | EXPECT_EQ(0, recurse.datasz); 232 | EXPECT_EQ(2, recurse.ptrs); 233 | capn_ptr recurse_mbr = capn_getp(recurse, 0, 1); 234 | EXPECT_EQ(CAPN_STRUCT, recurse_mbr.type); 235 | EXPECT_EQ(0, recurse_mbr.datasz); 236 | EXPECT_EQ(2, recurse_mbr.ptrs); 237 | EXPECT_EQ(recurse.seg, recurse_mbr.seg); 238 | EXPECT_EQ(recurse.data, recurse_mbr.data); 239 | EXPECT_EQ(CAPN_NULL, capn_getp(recurse, 1, 1).type); 240 | } 241 | 242 | TEST(WireFormat, StructRoundTrip_OneSegment) { 243 | Session ctx; 244 | setupStruct(&ctx.capn); 245 | 246 | // word count: 247 | // 1 root reference 248 | // 8 root struct 249 | // 1 sub message 250 | // 2 3-element int32 list 251 | // 13 struct list 252 | // 1 tag 253 | // 12 4x struct 254 | // 1 data segment 255 | // 1 reference segment 256 | // 1 sub-struct 257 | // 11 list list 258 | // 5 references to sub-lists 259 | // 6 sub-lists (4x 1 word, 1x 2 words) 260 | // 2 recurse 261 | // ----- 262 | // 38 263 | ASSERT_EQ(1, ctx.capn.segnum); 264 | EXPECT_EQ(38*8, ctx.capn.seglist->len); 265 | 266 | checkStruct(&ctx.capn); 267 | 268 | struct capn ctx2; 269 | memset(&ctx2, 0, sizeof(ctx2)); 270 | capn_append_segment(&ctx2, ctx.capn.seglist); 271 | checkStruct(&ctx2); 272 | } 273 | 274 | static struct capn_segment *CreateSmallSegment(void *u, uint32_t id, int sz) { 275 | struct capn_segment *s = (struct capn_segment*) calloc(1, sizeof(*s)); 276 | s->data = (char*) calloc(1, sz); 277 | s->cap = sz; 278 | return s; 279 | } 280 | 281 | static void getSegments(struct capn *c, struct capn_segment **s, size_t num) { 282 | ASSERT_EQ(num, c->segnum); 283 | 284 | s[0] = c->seglist; 285 | for (size_t i = 1; i < num; i++) { 286 | s[i] = s[i-1]->next; 287 | } 288 | 289 | for (size_t i = 0; i < num; i++) { 290 | EXPECT_EQ(s[i]->id, i); 291 | } 292 | } 293 | 294 | TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation) { 295 | Session ctx; 296 | ctx.capn.create = &CreateSmallSegment; 297 | 298 | setupStruct(&ctx.capn); 299 | 300 | struct capn_segment *segments[16]; 301 | getSegments(&ctx.capn, segments, 16); 302 | 303 | // Check that each segment has the expected size. Recall that the first word of each segment will 304 | // actually be a reference to the first thing allocated within that segment. 305 | EXPECT_EQ( 8, segments[ 0]->len); // root ref 306 | EXPECT_EQ(72, segments[ 1]->len); // root struct 307 | EXPECT_EQ(16, segments[ 2]->len); // sub-struct 308 | EXPECT_EQ(24, segments[ 3]->len); // 3-element int32 list 309 | EXPECT_EQ(80, segments[ 4]->len); // struct list 310 | EXPECT_EQ(16, segments[ 5]->len); // struct list substruct 1 311 | EXPECT_EQ(16, segments[ 6]->len); // struct list substruct 2 312 | EXPECT_EQ(16, segments[ 7]->len); // struct list substruct 3 313 | EXPECT_EQ(16, segments[ 8]->len); // struct list substruct 4 314 | EXPECT_EQ(48, segments[ 9]->len); // list list 315 | EXPECT_EQ(16, segments[10]->len); // list list sublist 1 316 | EXPECT_EQ(16, segments[11]->len); // list list sublist 2 317 | EXPECT_EQ(16, segments[12]->len); // list list sublist 3 318 | EXPECT_EQ(16, segments[13]->len); // list list sublist 4 319 | EXPECT_EQ(24, segments[14]->len); // list list sublist 5 320 | EXPECT_EQ(24, segments[15]->len); // recurse struct 321 | 322 | checkStruct(&ctx.capn); 323 | 324 | struct capn ctx2; 325 | memset(&ctx2, 0, sizeof(ctx2)); 326 | for (size_t i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { 327 | capn_append_segment(&ctx2, segments[i]); 328 | } 329 | 330 | checkStruct(&ctx2); 331 | } 332 | 333 | TEST(WireFormat, StructRoundTrip_OneSegmentPerAllocation_NoTag) { 334 | Session ctx; 335 | ctx.capn.create = &CreateSmallSegment; 336 | 337 | g_AddTag = 0; 338 | setupStruct(&ctx.capn); 339 | g_AddTag = 1; 340 | 341 | struct capn_segment *segments[31]; 342 | getSegments(&ctx.capn, segments, 31); 343 | 344 | // Check that each segment has the expected size. Note that we have plenty 345 | // of 16 byte double far ptrs. 346 | EXPECT_EQ( 8, segments[ 0]->len); // root ref 347 | EXPECT_EQ(64, segments[ 1]->len); // root struct 348 | EXPECT_EQ(16, segments[ 2]->len); // root struct ptr 349 | EXPECT_EQ( 8, segments[ 3]->len); // sub-struct 350 | EXPECT_EQ(16, segments[ 4]->len); // sub-struct ptr 351 | EXPECT_EQ(16, segments[ 5]->len); // 3-element int32 list 352 | EXPECT_EQ(16, segments[ 6]->len); // 3-element int32 list ptr 353 | EXPECT_EQ(72, segments[ 7]->len); // struct list 354 | EXPECT_EQ(16, segments[ 8]->len); // struct list ptr 355 | EXPECT_EQ( 8, segments[ 9]->len); // struct list substruct 1 356 | EXPECT_EQ(16, segments[10]->len); // struct list substruct 1 ptr 357 | EXPECT_EQ( 8, segments[11]->len); // struct list substruct 2 358 | EXPECT_EQ(16, segments[12]->len); // struct list substruct 2 ptr 359 | EXPECT_EQ( 8, segments[13]->len); // struct list substruct 3 360 | EXPECT_EQ(16, segments[14]->len); // struct list substruct 3 ptr 361 | EXPECT_EQ( 8, segments[15]->len); // struct list substruct 4 362 | EXPECT_EQ(16, segments[16]->len); // struct list substruct 4 ptr 363 | EXPECT_EQ(40, segments[17]->len); // list list 364 | EXPECT_EQ(16, segments[18]->len); // list list ptr 365 | EXPECT_EQ( 8, segments[19]->len); // list list sublist 1 366 | EXPECT_EQ(16, segments[20]->len); // list list sublist 1 ptr 367 | EXPECT_EQ( 8, segments[21]->len); // list list sublist 2 368 | EXPECT_EQ(16, segments[22]->len); // list list sublist 2 ptr 369 | EXPECT_EQ( 8, segments[23]->len); // list list sublist 3 370 | EXPECT_EQ(16, segments[24]->len); // list list sublist 3 ptr 371 | EXPECT_EQ( 8, segments[25]->len); // list list sublist 4 372 | EXPECT_EQ(16, segments[26]->len); // list list sublist 4 ptr 373 | EXPECT_EQ(16, segments[27]->len); // list list sublist 5 374 | EXPECT_EQ(16, segments[28]->len); // list list sublist 5 ptr 375 | EXPECT_EQ(16, segments[29]->len); // recurse struct 376 | EXPECT_EQ(16, segments[30]->len); // recurse struct ptr 377 | 378 | checkStruct(&ctx.capn); 379 | 380 | struct capn ctx2; 381 | memset(&ctx2, 0, sizeof(ctx2)); 382 | for (size_t i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { 383 | capn_append_segment(&ctx2, segments[i]); 384 | } 385 | 386 | checkStruct(&ctx2); 387 | } 388 | 389 | 390 | static struct capn_segment *CreateSegment64(void *u, uint32_t id, int sz) { 391 | if (sz < 64) { 392 | sz = 64; 393 | } 394 | struct capn_segment *s = (struct capn_segment*) calloc(1, sizeof(*s)); 395 | s->data = (char*) calloc(1, sz); 396 | s->cap = sz; 397 | return s; 398 | } 399 | 400 | TEST(WireFormat, StructRoundTrip_MultipleSegmentsWithMultipleAllocations) { 401 | Session ctx; 402 | ctx.capn.create = &CreateSegment64; 403 | 404 | setupStruct(&ctx.capn); 405 | 406 | // Verify that we made 6 segments. 407 | ASSERT_EQ(6, ctx.capn.segnum); 408 | 409 | struct capn_segment *segments[6]; 410 | segments[0] = ctx.capn.seglist; 411 | for (int i = 1; i < 6; i++) { 412 | segments[i] = segments[i-1]->next; 413 | } 414 | 415 | for (int i = 0; i < 6; i++) { 416 | EXPECT_EQ(segments[i]->id, i); 417 | } 418 | 419 | // Check that each segment has the expected size. Recall that each object will be prefixed by an 420 | // extra word if its parent is in a different segment. 421 | EXPECT_EQ(64, segments[0]->len); // root ref (8), sub-struct (8+tag), 3-element list (16+tag), list substruct 1 (8+tag) 422 | EXPECT_EQ(72, segments[1]->len); // root struct (64+tag) 423 | EXPECT_EQ(80, segments[2]->len); // struct list (72+tag) 424 | EXPECT_EQ(64, segments[3]->len); // list substruct 2,3,4 3*(8+tag), sublist 3 (8+tag) 425 | EXPECT_EQ(64, segments[4]->len); // list list (40+tag), sublist 1,2 2*8 426 | EXPECT_EQ(64, segments[5]->len); // sublist 4 (8+tag), 5 (16+tag), recurse struct (16+tag) 427 | 428 | checkStruct(&ctx.capn); 429 | 430 | struct capn ctx2; 431 | memset(&ctx2, 0, sizeof(ctx2)); 432 | for (size_t i = 0; i < sizeof(segments)/sizeof(segments[0]); i++) { 433 | capn_append_segment(&ctx2, segments[i]); 434 | } 435 | 436 | checkStruct(&ctx2); 437 | } 438 | 439 | TEST(WireFormat, CopyStruct) { 440 | Session ctx1, ctx2; 441 | setupStruct(&ctx1.capn); 442 | checkStruct(&ctx1.capn); 443 | 444 | capn_ptr root = capn_root(&ctx2.capn); 445 | EXPECT_EQ(0, capn_setp(root, 0, capn_getp(capn_root(&ctx1.capn), 0, 1))); 446 | 447 | checkStruct(&ctx2.capn); 448 | } 449 | 450 | int main(int argc, char *argv[]) { 451 | testing::InitGoogleTest(&argc, argv); 452 | return RUN_ALL_TESTS(); 453 | } 454 | 455 | -------------------------------------------------------------------------------- /compiler/schema.capnp: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 | # Licensed under the MIT License: 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | using C = import "c.capnp"; 23 | using Cxx = import "c++.capnp"; 24 | 25 | @0xa93fc509624c72d9; 26 | $Cxx.namespace("capnp::schema"); 27 | 28 | $C.fieldgetset; 29 | 30 | using Id = UInt64; 31 | # The globally-unique ID of a file, type, or annotation. 32 | 33 | struct Node { 34 | id @0 :Id; 35 | 36 | displayName @1 :Text; 37 | # Name to present to humans to identify this Node. You should not attempt to parse this. Its 38 | # format could change. It is not guaranteed to be unique. 39 | # 40 | # (On Zooko's triangle, this is the node's nickname.) 41 | 42 | displayNamePrefixLength @2 :UInt32; 43 | # If you want a shorter version of `displayName` (just naming this node, without its surrounding 44 | # scope), chop off this many characters from the beginning of `displayName`. 45 | 46 | scopeId @3 :Id; 47 | # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back 48 | # at this node, but robust code should avoid relying on this (and, in fact, group nodes are not 49 | # listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is 50 | # zero if the node has no parent, which is normally only the case with files, but should be 51 | # allowed for any kind of node (in order to make runtime type generation easier). 52 | 53 | parameters @32 :List(Parameter); 54 | # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. 55 | 56 | isGeneric @33 :Bool; 57 | # True if this node is generic, meaning that it or one of its parent scopes has a non-empty 58 | # `parameters`. 59 | 60 | struct Parameter { 61 | # Information about one of the node's parameters. 62 | 63 | name @0 :Text; 64 | } 65 | 66 | nestedNodes @4 :List(NestedNode); 67 | # List of nodes nested within this node, along with the names under which they were declared. 68 | 69 | struct NestedNode { 70 | name @0 :Text; 71 | # Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically. 72 | # 73 | # (On Zooko's triangle, this is the node's petname according to its parent scope.) 74 | 75 | id @1 :Id; 76 | # ID of the nested node. Typically, the target node's scopeId points back to this node, but 77 | # robust code should avoid relying on this. 78 | } 79 | 80 | annotations @5 :List(Annotation); 81 | # Annotations applied to this node. 82 | 83 | union { 84 | # Info specific to each kind of node. 85 | 86 | file @6 :Void; 87 | 88 | struct :group { 89 | dataWordCount @7 :UInt16; 90 | # Size of the data section, in words. 91 | 92 | pointerCount @8 :UInt16; 93 | # Size of the pointer section, in pointers (which are one word each). 94 | 95 | preferredListEncoding @9 :ElementSize; 96 | # The preferred element size to use when encoding a list of this struct. If this is anything 97 | # other than `inlineComposite` then the struct is one word or less in size and is a candidate 98 | # for list packing optimization. 99 | 100 | isGroup @10 :Bool; 101 | # If true, then this "struct" node is actually not an independent node, but merely represents 102 | # some named union or group within a particular parent struct. This node's scopeId refers 103 | # to the parent struct, which may itself be a union/group in yet another struct. 104 | # 105 | # All group nodes share the same dataWordCount and pointerCount as the top-level 106 | # struct, and their fields live in the same ordinal and offset spaces as all other fields in 107 | # the struct. 108 | # 109 | # Note that a named union is considered a special kind of group -- in fact, a named union 110 | # is exactly equivalent to a group that contains nothing but an unnamed union. 111 | 112 | discriminantCount @11 :UInt16; 113 | # Number of fields in this struct which are members of an anonymous union, and thus may 114 | # overlap. If this is non-zero, then a 16-bit discriminant is present indicating which 115 | # of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be 116 | # two or more. 117 | # 118 | # Note that the fields of an unnamed union are considered fields of the scope containing the 119 | # union -- an unnamed union is not its own group. So, a top-level struct may contain a 120 | # non-zero discriminant count. Named unions, on the other hand, are equivalent to groups 121 | # containing unnamed unions. So, a named union has its own independent schema node, with 122 | # `isGroup` = true. 123 | 124 | discriminantOffset @12 :UInt32; 125 | # If `discriminantCount` is non-zero, this is the offset of the union discriminant, in 126 | # multiples of 16 bits. 127 | 128 | fields @13 :List(Field); 129 | # Fields defined within this scope (either the struct's top-level fields, or the fields of 130 | # a particular group; see `isGroup`). 131 | # 132 | # The fields are sorted by ordinal number, but note that because groups share the same 133 | # ordinal space, the field's index in this list is not necessarily exactly its ordinal. 134 | # On the other hand, the field's position in this list does remain the same even as the 135 | # protocol evolves, since it is not possible to insert or remove an earlier ordinal. 136 | # Therefore, for most use cases, if you want to identify a field by number, it may make the 137 | # most sense to use the field's index in this list rather than its ordinal. 138 | } 139 | 140 | enum :group { 141 | enumerants@14 :List(Enumerant); 142 | # Enumerants ordered by numeric value (ordinal). 143 | } 144 | 145 | interface :group { 146 | methods @15 :List(Method); 147 | # Methods ordered by ordinal. 148 | 149 | superclasses @31 :List(Superclass); 150 | # Superclasses of this interface. 151 | } 152 | 153 | const :group { 154 | type @16 :Type; 155 | value @17 :Value; 156 | } 157 | 158 | annotation :group { 159 | type @18 :Type; 160 | 161 | targetsFile @19 :Bool; 162 | targetsConst @20 :Bool; 163 | targetsEnum @21 :Bool; 164 | targetsEnumerant @22 :Bool; 165 | targetsStruct @23 :Bool; 166 | targetsField @24 :Bool; 167 | targetsUnion @25 :Bool; 168 | targetsGroup @26 :Bool; 169 | targetsInterface @27 :Bool; 170 | targetsMethod @28 :Bool; 171 | targetsParam @29 :Bool; 172 | targetsAnnotation @30 :Bool; 173 | } 174 | } 175 | } 176 | 177 | struct Field { 178 | # Schema for a field of a struct. 179 | 180 | name @0 :Text; 181 | 182 | codeOrder @1 :UInt16; 183 | # Indicates where this member appeared in the code, relative to other members. 184 | # Code ordering may have semantic relevance -- programmers tend to place related fields 185 | # together. So, using code ordering makes sense in human-readable formats where ordering is 186 | # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum 187 | # value is count(members) - 1. Fields that are members of a union are only ordered relative to 188 | # the other members of that union, so the maximum value there is count(union.members). 189 | 190 | annotations @2 :List(Annotation); 191 | 192 | const noDiscriminant :UInt16 = 0xffff; 193 | 194 | discriminantValue @3 :UInt16 = Field.noDiscriminant; 195 | # If the field is in a union, this is the value which the union's discriminant should take when 196 | # the field is active. If the field is not in a union, this is 0xffff. 197 | 198 | union { 199 | slot :group { 200 | # A regular, non-group, non-fixed-list field. 201 | 202 | offset @4 :UInt32; 203 | # Offset, in units of the field's size, from the beginning of the section in which the field 204 | # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the 205 | # beginning of the data section. 206 | 207 | type @5 :Type; 208 | defaultValue @6 :Value; 209 | 210 | hadExplicitDefault @10 :Bool; 211 | # Whether the default value was specified explicitly. Non-explicit default values are always 212 | # zero or empty values. Usually, whether the default value was explicit shouldn't matter. 213 | # The main use case for this flag is for structs representing method parameters: 214 | # explicitly-defaulted parameters may be allowed to be omitted when calling the method. 215 | } 216 | 217 | group :group { 218 | # A group. 219 | 220 | typeId @7 :Id; 221 | # The ID of the group's node. 222 | } 223 | } 224 | 225 | ordinal :union { 226 | implicit @8 :Void; 227 | explicit @9 :UInt16; 228 | # The original ordinal number given to the field. You probably should NOT use this; if you need 229 | # a numeric identifier for a field, use its position within the field array for its scope. 230 | # The ordinal is given here mainly just so that the original schema text can be reproduced given 231 | # the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job. 232 | } 233 | } 234 | 235 | struct Enumerant { 236 | # Schema for member of an enum. 237 | 238 | name @0 :Text; 239 | 240 | codeOrder @1 :UInt16; 241 | # Specifies order in which the enumerants were declared in the code. 242 | # Like Struct.Field.codeOrder. 243 | 244 | annotations @2 :List(Annotation); 245 | } 246 | 247 | struct Superclass { 248 | id @0 :Id; 249 | brand @1 :Brand; 250 | } 251 | 252 | struct Method { 253 | # Schema for method of an interface. 254 | 255 | name @0 :Text; 256 | 257 | codeOrder @1 :UInt16; 258 | # Specifies order in which the methods were declared in the code. 259 | # Like Struct.Field.codeOrder. 260 | 261 | implicitParameters @7 :List(Node.Parameter); 262 | # The parameters listed in [] (typically, type / generic parameters), whose bindings are intended 263 | # to be inferred rather than specified explicitly, although not all languages support this. 264 | 265 | paramStructType @2 :Id; 266 | # ID of the parameter struct type. If a named parameter list was specified in the method 267 | # declaration (rather than a single struct parameter type) then a corresponding struct type is 268 | # auto-generated. Such an auto-generated type will not be listed in the interface's 269 | # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. 270 | # (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes 271 | # this a situation where you can't just climb the scope chain to find where a particular 272 | # generic parameter was introduced. Making the `scopeId` zero was a mistake.) 273 | 274 | paramBrand @5 :Brand; 275 | # Brand of param struct type. 276 | 277 | resultStructType @3 :Id; 278 | # ID of the return struct type; similar to `paramStructType`. 279 | 280 | resultBrand @6 :Brand; 281 | # Brand of result struct type. 282 | 283 | annotations @4 :List(Annotation); 284 | } 285 | 286 | struct Type { 287 | # Represents a type expression. 288 | 289 | union { 290 | # The ordinals intentionally match those of Value. 291 | 292 | void @0 :Void; 293 | bool @1 :Void; 294 | int8 @2 :Void; 295 | int16 @3 :Void; 296 | int32 @4 :Void; 297 | int64 @5 :Void; 298 | uint8 @6 :Void; 299 | uint16 @7 :Void; 300 | uint32 @8 :Void; 301 | uint64 @9 :Void; 302 | float32 @10 :Void; 303 | float64 @11 :Void; 304 | text @12 :Void; 305 | data @13 :Void; 306 | 307 | list :group { 308 | elementType @14 :Type; 309 | } 310 | 311 | enum :group { 312 | typeId @15 :Id; 313 | brand @21 :Brand; 314 | } 315 | struct :group { 316 | typeId @16 :Id; 317 | brand @22 :Brand; 318 | } 319 | interface :group { 320 | typeId @17 :Id; 321 | brand @23 :Brand; 322 | } 323 | 324 | anyPointer :union { 325 | unconstrained @18 :Void; 326 | # A regular AnyPointer. 327 | 328 | parameter :group { 329 | # This is actually a reference to a type parameter defined within this scope. 330 | 331 | scopeId @19 :Id; 332 | # ID of the generic type whose parameter we're referencing. This should be a parent of the 333 | # current scope. 334 | 335 | parameterIndex @20 :UInt16; 336 | # Index of the parameter within the generic type's parameter list. 337 | } 338 | 339 | implicitMethodParameter :group { 340 | # This is actually a reference to an implicit (generic) parameter of a method. The only 341 | # legal context for this type to appear is inside Method.paramBrand or Method.resultBrand. 342 | 343 | parameterIndex @24 :UInt16; 344 | } 345 | } 346 | } 347 | } 348 | 349 | struct Brand { 350 | # Specifies bindings for parameters of generics. Since these bindings turn a generic into a 351 | # non-generic, we call it the "brand". 352 | 353 | scopes @0 :List(Scope); 354 | # For each of the target type and each of its parent scopes, a parameterization may be included 355 | # in this list. If no parameterization is included for a particular relevant scope, then either 356 | # that scope has no parameters or all parameters should be considered to be `AnyPointer`. 357 | 358 | struct Scope { 359 | scopeId @0 :Id; 360 | # ID of the scope to which these params apply. 361 | 362 | union { 363 | bind @1 :List(Binding); 364 | # List of parameter bindings. 365 | 366 | inherit @2 :Void; 367 | # The place where this Brand appears is actually within this scope or a sub-scope, 368 | # and the bindings for this scope should be inherited from the reference point. 369 | } 370 | } 371 | 372 | struct Binding { 373 | union { 374 | unbound @0 :Void; 375 | type @1 :Type; 376 | 377 | # TODO(someday): Allow non-type parameters? Unsure if useful. 378 | } 379 | } 380 | } 381 | 382 | struct Value { 383 | # Represents a value, e.g. a field default value, constant value, or annotation value. 384 | 385 | union { 386 | # The ordinals intentionally match those of Type. 387 | 388 | void @0 :Void; 389 | bool @1 :Bool; 390 | int8 @2 :Int8; 391 | int16 @3 :Int16; 392 | int32 @4 :Int32; 393 | int64 @5 :Int64; 394 | uint8 @6 :UInt8; 395 | uint16 @7 :UInt16; 396 | uint32 @8 :UInt32; 397 | uint64 @9 :UInt64; 398 | float32 @10 :Float32; 399 | float64 @11 :Float64; 400 | text @12 :Text; 401 | data @13 :Data; 402 | 403 | list @14 :AnyPointer; 404 | 405 | enum @15 :UInt16; 406 | struct @16 :AnyPointer; 407 | 408 | interface @17 :Void; 409 | # The only interface value that can be represented statically is "null", whose methods always 410 | # throw exceptions. 411 | 412 | anyPointer @18 :AnyPointer; 413 | } 414 | } 415 | 416 | struct Annotation { 417 | # Describes an annotation applied to a declaration. Note AnnotationNode describes the 418 | # annotation's declaration, while this describes a use of the annotation. 419 | 420 | id @0 :Id; 421 | # ID of the annotation node. 422 | 423 | brand @2 :Brand; 424 | # Brand of the annotation. 425 | # 426 | # Note that the annotation itself is not allowed to be parameterized, but its scope might be. 427 | 428 | value @1 :Value; 429 | } 430 | 431 | enum ElementSize { 432 | # Possible element sizes for encoded lists. These correspond exactly to the possible values of 433 | # the 3-bit element size component of a list pointer. 434 | 435 | empty @0; # aka "void", but that's a keyword. 436 | bit @1; 437 | byte @2; 438 | twoBytes @3; 439 | fourBytes @4; 440 | eightBytes @5; 441 | pointer @6; 442 | inlineComposite @7; 443 | } 444 | 445 | struct CodeGeneratorRequest { 446 | nodes @0 :List(Node); 447 | # All nodes parsed by the compiler, including for the files on the command line and their 448 | # imports. 449 | 450 | requestedFiles @1 :List(RequestedFile); 451 | # Files which were listed on the command line. 452 | 453 | struct RequestedFile { 454 | id @0 :Id; 455 | # ID of the file. 456 | 457 | filename @1 :Text; 458 | # Name of the file as it appeared on the command-line (minus the src-prefix). You may use 459 | # this to decide where to write the output. 460 | 461 | imports @2 :List(Import); 462 | # List of all imported paths seen in this file. 463 | 464 | struct Import { 465 | id @0 :Id; 466 | # ID of the imported file. 467 | 468 | name @1 :Text; 469 | # Name which *this* file used to refer to the foreign file. This may be a relative name. 470 | # This information is provided because it might be useful for code generation, e.g. to 471 | # generate #include directives in C++. We don't put this in Node.file because this 472 | # information is only meaningful at compile time anyway. 473 | # 474 | # (On Zooko's triangle, this is the import's petname according to the importing file.) 475 | } 476 | } 477 | } 478 | -------------------------------------------------------------------------------- /compiler/schema-test.cpp: -------------------------------------------------------------------------------- 1 | /* schema-test.cpp 2 | * 3 | * Copyright (C) 2013 James McKaskill 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include "schema.capnp.h" 10 | #include 11 | 12 | static const uint8_t simple_schema[] = { 13 | 0x00, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 14 | 0x05, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x6d, 0x05, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 15 | 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x73, 0x4d, 0xd2, 0x75, 0x6b, 0xff, 0xe1, 0xbe, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x29, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 18 | 0x3d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 19 | 0x09, 0xb7, 0x71, 0x68, 0xc7, 0x34, 0xc8, 0xff, 0x73, 0x4d, 0xd2, 0x75, 0x6b, 0xff, 0xe1, 0xbe, 20 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 21 | 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 22 | 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 23 | 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x61, 0x70, 0x6e, 0x70, 0x00, 0x00, 0x00, 24 | 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x09, 0xb7, 0x71, 0x68, 0xc7, 0x34, 0xc8, 0xff, 25 | 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x46, 0x6f, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 28 | 0x2f, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x61, 0x70, 0x6e, 0x70, 0x3a, 0x46, 0x6f, 29 | 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 31 | 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 33 | 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 34 | 0x62, 0x6f, 0x64, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 36 | 0x4c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x29, 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 38 | 0x2c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x49, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 40 | 0x4c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0x69, 0x01, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 42 | 0x6c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x89, 0x01, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 44 | 0x8c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0xa9, 0x01, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0xad, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 46 | 0xac, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0xc9, 0x01, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0xcd, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 48 | 0xcc, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0xe9, 0x01, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 50 | 0xec, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x09, 0x02, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x0d, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 52 | 0x0c, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x29, 0x02, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x2d, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 54 | 0x2c, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x49, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x4d, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 56 | 0x4c, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0x69, 0x02, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6d, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 58 | 0x6c, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x89, 0x02, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x8d, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 60 | 0x8c, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0xa9, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0xad, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 62 | 0xac, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0xc9, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0xcd, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 64 | 0xcc, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0xe9, 0x02, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0xed, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 66 | 0xec, 0x02, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x09, 0x03, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 68 | 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x11, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x29, 0x03, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x2d, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 70 | 0x2c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x12, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 71 | 0x49, 0x03, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x4d, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 72 | 0x4c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x13, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x69, 0x03, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x6d, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 74 | 0x6c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 75 | 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 76 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 77 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 81 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 82 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 83 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x74, 0x38, 0x56, 0x61, 0x6c, 0x75, 87 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 88 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 89 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x56, 0x61, 0x6c, 93 | 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 94 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 95 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 99 | 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 100 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 101 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 105 | 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 106 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 107 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 109 | 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x69, 0x6e, 0x74, 0x38, 0x56, 0x61, 0x6c, 111 | 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 112 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 113 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 115 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x69, 0x6e, 0x74, 0x31, 0x36, 0x56, 0x61, 117 | 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 118 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 119 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 121 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 123 | 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 124 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 125 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 127 | 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x6f, 0x69, 0x64, 0x56, 0x61, 0x6c, 0x75, 129 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 131 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 133 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x32, 0x56, 135 | 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 136 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 137 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 139 | 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x36, 0x34, 0x56, 141 | 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 142 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 143 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 145 | 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x56, 0x61, 0x6c, 0x75, 147 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 149 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 151 | 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x56, 0x61, 0x6c, 0x75, 153 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 155 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157 | 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 159 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 161 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 163 | 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 165 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 166 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 167 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 169 | 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x56, 0x61, 171 | 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 173 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 | 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 177 | 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 179 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 181 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x56, 0x61, 183 | 0x6c, 0x75, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 185 | 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 187 | 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x4d, 0xd2, 0x75, 0x6b, 0xff, 0xe1, 0xbe, 189 | }; 190 | 191 | TEST(Schema, ReadSimple) { 192 | struct capn ctx; 193 | ASSERT_EQ(0, capn_init_mem(&ctx, simple_schema, sizeof(simple_schema), 0)); 194 | 195 | CodeGeneratorRequest_ptr root = {capn_getp(capn_root(&ctx), 0, 1)}; 196 | EXPECT_EQ(CAPN_STRUCT, root.p.type); 197 | 198 | struct CodeGeneratorRequest req; 199 | read_CodeGeneratorRequest(&req, root); 200 | for (int i = 0; i < req.nodes.p.len; i++) { 201 | } 202 | } 203 | 204 | -------------------------------------------------------------------------------- /compiler/test.capnp: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 | # Licensed under the MIT License: 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | @0xd508eebdc2dc42b8; 23 | 24 | using C = import "c.capnp"; 25 | using Cxx = import "c++.capnp"; 26 | 27 | $C.fieldgetset; 28 | 29 | # Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified 30 | # names for stuff in the capnproto namespace. 31 | $Cxx.namespace("capnproto_test::capnp::test"); 32 | 33 | enum TestEnum { 34 | foo @0; 35 | bar @1; 36 | baz @2; 37 | qux @3; 38 | quux @4; 39 | corge @5; 40 | grault @6; 41 | garply @7; 42 | } 43 | 44 | struct TestAllTypes { 45 | voidField @0 : Void; 46 | boolField @1 : Bool; 47 | int8Field @2 : Int8; 48 | int16Field @3 : Int16; 49 | int32Field @4 : Int32; 50 | int64Field @5 : Int64; 51 | uInt8Field @6 : UInt8; 52 | uInt16Field @7 : UInt16; 53 | uInt32Field @8 : UInt32; 54 | uInt64Field @9 : UInt64; 55 | float32Field @10 : Float32; 56 | float64Field @11 : Float64; 57 | textField @12 : Text; 58 | dataField @13 : Data; 59 | structField @14 : TestAllTypes; 60 | enumField @15 : TestEnum; 61 | interfaceField @16 : Void; # TODO 62 | 63 | voidList @17 : List(Void); 64 | boolList @18 : List(Bool); 65 | int8List @19 : List(Int8); 66 | int16List @20 : List(Int16); 67 | int32List @21 : List(Int32); 68 | int64List @22 : List(Int64); 69 | uInt8List @23 : List(UInt8); 70 | uInt16List @24 : List(UInt16); 71 | uInt32List @25 : List(UInt32); 72 | uInt64List @26 : List(UInt64); 73 | float32List @27 : List(Float32); 74 | float64List @28 : List(Float64); 75 | textList @29 : List(Text); 76 | dataList @30 : List(Data); 77 | structList @31 : List(TestAllTypes); 78 | enumList @32 : List(TestEnum); 79 | interfaceList @33 : List(Void); # TODO 80 | } 81 | 82 | struct TestDefaults { 83 | voidField @0 : Void = void; 84 | boolField @1 : Bool = true; 85 | int8Field @2 : Int8 = -123; 86 | int16Field @3 : Int16 = -12345; 87 | int32Field @4 : Int32 = -12345678; 88 | int64Field @5 : Int64 = -123456789012345; 89 | uInt8Field @6 : UInt8 = 234; 90 | uInt16Field @7 : UInt16 = 45678; 91 | uInt32Field @8 : UInt32 = 3456789012; 92 | uInt64Field @9 : UInt64 = 12345678901234567890; 93 | float32Field @10 : Float32 = 1234.5; 94 | float64Field @11 : Float64 = -123e45; 95 | textField @12 : Text = "foo"; 96 | dataField @13 : Data = 0x"62 61 72"; # "bar" 97 | structField @14 : TestAllTypes = ( 98 | voidField = void, 99 | boolField = true, 100 | int8Field = -12, 101 | int16Field = 3456, 102 | int32Field = -78901234, 103 | int64Field = 56789012345678, 104 | uInt8Field = 90, 105 | uInt16Field = 1234, 106 | uInt32Field = 56789012, 107 | uInt64Field = 345678901234567890, 108 | float32Field = -1.25e-10, 109 | float64Field = 345, 110 | textField = "baz", 111 | dataField = "qux", 112 | structField = ( 113 | textField = "nested", 114 | structField = (textField = "really nested")), 115 | enumField = baz, 116 | # interfaceField can't have a default 117 | 118 | voidList = [void, void, void], 119 | boolList = [false, true, false, true, true], 120 | int8List = [12, -34, -0x80, 0x7f], 121 | int16List = [1234, -5678, -0x8000, 0x7fff], 122 | int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], 123 | int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], 124 | uInt8List = [12, 34, 0, 0xff], 125 | uInt16List = [1234, 5678, 0, 0xffff], 126 | uInt32List = [12345678, 90123456, 0, 0xffffffff], 127 | uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], 128 | float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], 129 | float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], 130 | textList = ["quux", "corge", "grault"], 131 | dataList = ["garply", "waldo", "fred"], 132 | structList = [ 133 | (textField = "x structlist 1"), 134 | (textField = "x structlist 2"), 135 | (textField = "x structlist 3")], 136 | enumList = [qux, bar, grault] 137 | # interfaceList can't have a default 138 | ); 139 | enumField @15 : TestEnum = corge; 140 | interfaceField @16 : Void; # TODO 141 | 142 | voidList @17 : List(Void) = [void, void, void, void, void, void]; 143 | boolList @18 : List(Bool) = [true, false, false, true]; 144 | int8List @19 : List(Int8) = [111, -111]; 145 | int16List @20 : List(Int16) = [11111, -11111]; 146 | int32List @21 : List(Int32) = [111111111, -111111111]; 147 | int64List @22 : List(Int64) = [1111111111111111111, -1111111111111111111]; 148 | uInt8List @23 : List(UInt8) = [111, 222] ; 149 | uInt16List @24 : List(UInt16) = [33333, 44444]; 150 | uInt32List @25 : List(UInt32) = [3333333333]; 151 | uInt64List @26 : List(UInt64) = [11111111111111111111]; 152 | float32List @27 : List(Float32) = [5555.5, inf, -inf, nan]; 153 | float64List @28 : List(Float64) = [7777.75, inf, -inf, nan]; 154 | textList @29 : List(Text) = ["plugh", "xyzzy", "thud"]; 155 | dataList @30 : List(Data) = ["oops", "exhausted", "rfc3092"]; 156 | structList @31 : List(TestAllTypes) = [ 157 | (textField = "structlist 1"), 158 | (textField = "structlist 2"), 159 | (textField = "structlist 3")]; 160 | enumList @32 : List(TestEnum) = [foo, garply]; 161 | interfaceList @33 : List(Void); # TODO 162 | } 163 | 164 | struct TestAnyPointer { 165 | anyPointerField @0 :AnyPointer; 166 | 167 | # Do not add any other fields here! Some tests rely on anyPointerField being the last pointer 168 | # in the struct. 169 | } 170 | 171 | struct TestOutOfOrder { 172 | foo @3 :Text; 173 | bar @2 :Text; 174 | baz @8 :Text; 175 | qux @0 :Text; 176 | quux @6 :Text; 177 | corge @4 :Text; 178 | grault @1 :Text; 179 | garply @7 :Text; 180 | waldo @5 :Text; 181 | } 182 | 183 | struct TestUnion { 184 | union0 @0! :union { 185 | # Pack union 0 under ideal conditions: there is no unused padding space prior to it. 186 | u0f0s0 @4: Void; 187 | u0f0s1 @5: Bool; 188 | u0f0s8 @6: Int8; 189 | u0f0s16 @7: Int16; 190 | u0f0s32 @8: Int32; 191 | u0f0s64 @9: Int64; 192 | u0f0sp @10: Text; 193 | 194 | # Pack more stuff into union0 -- should go in same space. 195 | u0f1s0 @11: Void; 196 | u0f1s1 @12: Bool; 197 | u0f1s8 @13: Int8; 198 | u0f1s16 @14: Int16; 199 | u0f1s32 @15: Int32; 200 | u0f1s64 @16: Int64; 201 | u0f1sp @17: Text; 202 | } 203 | 204 | # Pack one bit in order to make pathological situation for union1. 205 | bit0 @18: Bool; 206 | 207 | union1 @1! :union { 208 | # Pack pathologically bad case. Each field takes up new space. 209 | u1f0s0 @19: Void; 210 | u1f0s1 @20: Bool; 211 | u1f1s1 @21: Bool; 212 | u1f0s8 @22: Int8; 213 | u1f1s8 @23: Int8; 214 | u1f0s16 @24: Int16; 215 | u1f1s16 @25: Int16; 216 | u1f0s32 @26: Int32; 217 | u1f1s32 @27: Int32; 218 | u1f0s64 @28: Int64; 219 | u1f1s64 @29: Int64; 220 | u1f0sp @30: Text; 221 | u1f1sp @31: Text; 222 | 223 | # Pack more stuff into union1 -- each should go into the same space as corresponding u1f0s*. 224 | u1f2s0 @32: Void; 225 | u1f2s1 @33: Bool; 226 | u1f2s8 @34: Int8; 227 | u1f2s16 @35: Int16; 228 | u1f2s32 @36: Int32; 229 | u1f2s64 @37: Int64; 230 | u1f2sp @38: Text; 231 | } 232 | 233 | # Fill in the rest of that bitfield from earlier. 234 | bit2 @39: Bool; 235 | bit3 @40: Bool; 236 | bit4 @41: Bool; 237 | bit5 @42: Bool; 238 | bit6 @43: Bool; 239 | bit7 @44: Bool; 240 | 241 | # Interleave two unions to be really annoying. 242 | # Also declare in reverse order to make sure union discriminant values are sorted by field number 243 | # and not by declaration order. 244 | union2 @2! :union { 245 | u2f0s64 @54: Int64; 246 | u2f0s32 @52: Int32; 247 | u2f0s16 @50: Int16; 248 | u2f0s8 @47: Int8; 249 | u2f0s1 @45: Bool; 250 | } 251 | 252 | union3 @3! :union { 253 | u3f0s64 @55: Int64; 254 | u3f0s32 @53: Int32; 255 | u3f0s16 @51: Int16; 256 | u3f0s8 @48: Int8; 257 | u3f0s1 @46: Bool; 258 | } 259 | 260 | byte0 @49: UInt8; 261 | } 262 | 263 | struct TestUnnamedUnion { 264 | before @0 :Text; 265 | 266 | union { 267 | foo @1 :UInt16; 268 | bar @3 :UInt32; 269 | } 270 | 271 | middle @2 :UInt16; 272 | 273 | after @4 :Text; 274 | } 275 | 276 | struct TestUnionInUnion { 277 | # There is no reason to ever do this. 278 | outer :union { 279 | inner :union { 280 | foo @0 :Int32; 281 | bar @1 :Int32; 282 | } 283 | baz @2 :Int32; 284 | } 285 | } 286 | 287 | struct TestGroups { 288 | groups :union { 289 | foo :group { 290 | corge @0 :Int32; 291 | grault @2 :Int64; 292 | garply @8 :Text; 293 | } 294 | bar :group { 295 | corge @3 :Int32; 296 | grault @4 :Text; 297 | garply @5 :Int64; 298 | } 299 | baz :group { 300 | corge @1 :Int32; 301 | grault @6 :Text; 302 | garply @7 :Text; 303 | } 304 | } 305 | } 306 | 307 | struct TestInterleavedGroups { 308 | group1 :group { 309 | foo @0 :UInt32; 310 | bar @2 :UInt64; 311 | union { 312 | qux @4 :UInt16; 313 | corge :group { 314 | grault @6 :UInt64; 315 | garply @8 :UInt16; 316 | plugh @14 :Text; 317 | xyzzy @16 :Text; 318 | } 319 | 320 | fred @12 :Text; 321 | } 322 | 323 | waldo @10 :Text; 324 | } 325 | 326 | group2 :group { 327 | foo @1 :UInt32; 328 | bar @3 :UInt64; 329 | union { 330 | qux @5 :UInt16; 331 | corge :group { 332 | grault @7 :UInt64; 333 | garply @9 :UInt16; 334 | plugh @15 :Text; 335 | xyzzy @17 :Text; 336 | } 337 | 338 | fred @13 :Text; 339 | } 340 | 341 | waldo @11 :Text; 342 | } 343 | } 344 | 345 | struct TestUnionDefaults { 346 | s16s8s64s8Set @0 :TestUnion = 347 | (union0 = (u0f0s16 = 321), union1 = (u1f0s8 = 123), union2 = (u2f0s64 = 12345678901234567), 348 | union3 = (u3f0s8 = 55)); 349 | s0sps1s32Set @1 :TestUnion = 350 | (union0 = (u0f1s0 = void), union1 = (u1f0sp = "foo"), union2 = (u2f0s1 = true), 351 | union3 = (u3f0s32 = 12345678)); 352 | 353 | unnamed1 @2 :TestUnnamedUnion = (foo = 123); 354 | unnamed2 @3 :TestUnnamedUnion = (bar = 321, before = "foo", after = "bar"); 355 | } 356 | 357 | struct TestNestedTypes { 358 | enum NestedEnum { 359 | foo @0; 360 | bar @1; 361 | } 362 | 363 | struct NestedStruct { 364 | enum NestedEnum { 365 | baz @0; 366 | qux @1; 367 | quux @2; 368 | } 369 | 370 | outerNestedEnum @0 :TestNestedTypes.NestedEnum = bar; 371 | innerNestedEnum @1 :NestedEnum = quux; 372 | } 373 | 374 | nestedStruct @0 :NestedStruct; 375 | 376 | outerNestedEnum @1 :NestedEnum = bar; 377 | innerNestedEnum @2 :NestedStruct.NestedEnum = quux; 378 | } 379 | 380 | struct TestUsing { 381 | using OuterNestedEnum = TestNestedTypes.NestedEnum; 382 | using TestNestedTypes.NestedStruct.NestedEnum; 383 | 384 | outerNestedEnum @1 :OuterNestedEnum = bar; 385 | innerNestedEnum @0 :NestedEnum = quux; 386 | } 387 | 388 | struct TestLists { 389 | # Small structs, when encoded as list, will be encoded as primitive lists rather than struct 390 | # lists, to save space. 391 | struct Struct0 { f @0 :Void; } 392 | struct Struct1 { f @0 :Bool; } 393 | struct Struct8 { f @0 :UInt8; } 394 | struct Struct16 { f @0 :UInt16; } 395 | struct Struct32 { f @0 :UInt32; } 396 | struct Struct64 { f @0 :UInt64; } 397 | struct StructP { f @0 :Text; } 398 | 399 | # Versions of the above which cannot be encoded as primitive lists. 400 | struct Struct0c { f @0 :Void; pad @1 :Text; } 401 | struct Struct1c { f @0 :Bool; pad @1 :Text; } 402 | struct Struct8c { f @0 :UInt8; pad @1 :Text; } 403 | struct Struct16c { f @0 :UInt16; pad @1 :Text; } 404 | struct Struct32c { f @0 :UInt32; pad @1 :Text; } 405 | struct Struct64c { f @0 :UInt64; pad @1 :Text; } 406 | struct StructPc { f @0 :Text; pad @1 :UInt64; } 407 | 408 | list0 @0 :List(Struct0); 409 | list1 @1 :List(Struct1); 410 | list8 @2 :List(Struct8); 411 | list16 @3 :List(Struct16); 412 | list32 @4 :List(Struct32); 413 | list64 @5 :List(Struct64); 414 | listP @6 :List(StructP); 415 | 416 | int32ListList @7 :List(List(Int32)); 417 | textListList @8 :List(List(Text)); 418 | structListList @9 :List(List(TestAllTypes)); 419 | } 420 | 421 | struct TestFieldZeroIsBit { 422 | bit @0 :Bool; 423 | secondBit @1 :Bool = true; 424 | thirdField @2 :UInt8 = 123; 425 | } 426 | 427 | struct TestListDefaults { 428 | lists @0 :TestLists = ( 429 | list0 = [(f = void), (f = void)], 430 | list1 = [(f = true), (f = false), (f = true), (f = true)], 431 | list8 = [(f = 123), (f = 45)], 432 | list16 = [(f = 12345), (f = 6789)], 433 | list32 = [(f = 123456789), (f = 234567890)], 434 | list64 = [(f = 1234567890123456), (f = 2345678901234567)], 435 | listP = [(f = "foo"), (f = "bar")], 436 | int32ListList = [[1, 2, 3], [4, 5], [12341234]], 437 | textListList = [["foo", "bar"], ["baz"], ["qux", "corge"]], 438 | structListList = [[(int32Field = 123), (int32Field = 456)], [(int32Field = 789)]]); 439 | } 440 | 441 | struct TestLateUnion { 442 | # Test what happens if the unions are not the first ordinals in the struct. At one point this 443 | # was broken for the dynamic API. 444 | 445 | foo @0 :Int32; 446 | bar @1 :Text; 447 | baz @2 :Int16; 448 | 449 | theUnion @3! :union { 450 | qux @4 :Text; 451 | corge @5 :List(Int32); 452 | grault @6 :Float32; 453 | } 454 | 455 | anotherUnion @7! :union { 456 | qux @8 :Text; 457 | corge @9 :List(Int32); 458 | grault @10 :Float32; 459 | } 460 | } 461 | 462 | struct TestOldVersion { 463 | # A subset of TestNewVersion. 464 | old1 @0 :Int64; 465 | old2 @1 :Text; 466 | old3 @2 :TestOldVersion; 467 | } 468 | 469 | struct TestNewVersion { 470 | # A superset of TestOldVersion. 471 | old1 @0 :Int64; 472 | old2 @1 :Text; 473 | old3 @2 :TestNewVersion; 474 | new1 @3 :Int64 = 987; 475 | new2 @4 :Text = "baz"; 476 | } 477 | 478 | struct TestStructUnion { 479 | un @0! :union { 480 | struct @1 :SomeStruct; 481 | object @2 :TestAnyPointer; 482 | } 483 | 484 | struct SomeStruct { 485 | someText @0 :Text; 486 | moreText @1 :Text; 487 | } 488 | } 489 | 490 | struct TestPrintInlineStructs { 491 | someText @0 :Text; 492 | 493 | structList @1 :List(InlineStruct); 494 | struct InlineStruct { 495 | int32Field @0 :Int32; 496 | textField @1 :Text; 497 | } 498 | } 499 | 500 | struct TestWholeFloatDefault { 501 | # At one point, these failed to compile in C++ because it would produce literals like "123f", 502 | # which is not valid; it needs to be "123.0f". 503 | field @0 :Float32 = 123; 504 | bigField @1 :Float32 = 2e30; 505 | const constant :Float32 = 456; 506 | const bigConstant :Float32 = 4e30; 507 | } 508 | 509 | struct TestEmptyStruct {} 510 | 511 | struct TestConstants { 512 | const voidConst :Void = void; 513 | const boolConst :Bool = true; 514 | const int8Const :Int8 = -123; 515 | const int16Const :Int16 = -12345; 516 | const int32Const :Int32 = -12345678; 517 | const int64Const :Int64 = -123456789012345; 518 | const uint8Const :UInt8 = 234; 519 | const uint16Const :UInt16 = 45678; 520 | const uint32Const :UInt32 = 3456789012; 521 | const uint64Const :UInt64 = 12345678901234567890; 522 | const float32Const :Float32 = 1234.5; 523 | const float64Const :Float64 = -123e45; 524 | const textConst :Text = "foo"; 525 | const dataConst :Data = "bar"; 526 | const structConst :TestAllTypes = ( 527 | voidField = void, 528 | boolField = true, 529 | int8Field = -12, 530 | int16Field = 3456, 531 | int32Field = -78901234, 532 | int64Field = 56789012345678, 533 | uInt8Field = 90, 534 | uInt16Field = 1234, 535 | uInt32Field = 56789012, 536 | uInt64Field = 345678901234567890, 537 | float32Field = -1.25e-10, 538 | float64Field = 345, 539 | textField = "baz", 540 | dataField = "qux", 541 | structField = ( 542 | textField = "nested", 543 | structField = (textField = "really nested")), 544 | enumField = baz, 545 | # interfaceField can't have a default 546 | 547 | voidList = [void, void, void], 548 | boolList = [false, true, false, true, true], 549 | int8List = [12, -34, -0x80, 0x7f], 550 | int16List = [1234, -5678, -0x8000, 0x7fff], 551 | int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], 552 | int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], 553 | uInt8List = [12, 34, 0, 0xff], 554 | uInt16List = [1234, 5678, 0, 0xffff], 555 | uInt32List = [12345678, 90123456, 0, 0xffffffff], 556 | uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], 557 | float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], 558 | float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], 559 | textList = ["quux", "corge", "grault"], 560 | dataList = ["garply", "waldo", "fred"], 561 | structList = [ 562 | (textField = "x structlist 1"), 563 | (textField = "x structlist 2"), 564 | (textField = "x structlist 3")], 565 | enumList = [qux, bar, grault] 566 | # interfaceList can't have a default 567 | ); 568 | const enumConst :TestEnum = corge; 569 | 570 | const voidListConst :List(Void) = [void, void, void, void, void, void]; 571 | const boolListConst :List(Bool) = [true, false, false, true]; 572 | const int8ListConst :List(Int8) = [111, -111]; 573 | const int16ListConst :List(Int16) = [11111, -11111]; 574 | const int32ListConst :List(Int32) = [111111111, -111111111]; 575 | const int64ListConst :List(Int64) = [1111111111111111111, -1111111111111111111]; 576 | const uint8ListConst :List(UInt8) = [111, 222] ; 577 | const uint16ListConst :List(UInt16) = [33333, 44444]; 578 | const uint32ListConst :List(UInt32) = [3333333333]; 579 | const uint64ListConst :List(UInt64) = [11111111111111111111]; 580 | const float32ListConst :List(Float32) = [5555.5, inf, -inf, nan]; 581 | const float64ListConst :List(Float64) = [7777.75, inf, -inf, nan]; 582 | const textListConst :List(Text) = ["plugh", "xyzzy", "thud"]; 583 | const dataListConst :List(Data) = ["oops", "exhausted", "rfc3092"]; 584 | const structListConst :List(TestAllTypes) = [ 585 | (textField = "structlist 1"), 586 | (textField = "structlist 2"), 587 | (textField = "structlist 3")]; 588 | const enumListConst :List(TestEnum) = [foo, garply]; 589 | } 590 | 591 | const globalInt :UInt32 = 12345; 592 | const globalText :Text = "foobar"; 593 | const globalStruct :TestAllTypes = (int32Field = 54321); 594 | const globalPrintableStruct :TestPrintInlineStructs = (someText = "foo"); 595 | const derivedConstant :TestAllTypes = ( 596 | uInt32Field = .globalInt, 597 | textField = TestConstants.textConst, 598 | structField = TestConstants.structConst, 599 | int16List = TestConstants.int16ListConst, 600 | structList = TestConstants.structListConst); 601 | 602 | struct TestSturdyRef { 603 | hostId @0 :TestSturdyRefHostId; 604 | objectId @1 :AnyPointer; 605 | } 606 | 607 | struct TestSturdyRefHostId { 608 | host @0 :Text; 609 | } 610 | 611 | struct TestSturdyRefObjectId { 612 | tag @0 :Tag; 613 | enum Tag { 614 | testInterface @0; 615 | testExtends @1; 616 | testPipeline @2; 617 | testTailCallee @3; 618 | testTailCaller @4; 619 | testMoreStuff @5; 620 | } 621 | } 622 | 623 | struct TestProvisionId {} 624 | struct TestRecipientId {} 625 | struct TestThirdPartyCapId {} 626 | struct TestJoinResult {} 627 | 628 | struct TestNameAnnotation $Cxx.name("RenamedStruct") { 629 | union { 630 | badFieldName @0 :Bool $Cxx.name("goodFieldName"); 631 | bar @1 :Int8; 632 | } 633 | 634 | enum BadlyNamedEnum $Cxx.name("RenamedEnum") { 635 | foo @0; 636 | bar @1; 637 | baz @2 $Cxx.name("qux"); 638 | } 639 | 640 | anotherBadFieldName @2 :BadlyNamedEnum $Cxx.name("anotherGoodFieldName"); 641 | 642 | struct NestedStruct $Cxx.name("RenamedNestedStruct") { 643 | badNestedFieldName @0 :Bool $Cxx.name("goodNestedFieldName"); 644 | anotherBadNestedFieldName @1 :NestedStruct $Cxx.name("anotherGoodNestedFieldName"); 645 | 646 | enum DeeplyNestedEnum $Cxx.name("RenamedDeeplyNestedEnum") { 647 | quux @0; 648 | corge @1; 649 | grault @2 $Cxx.name("garply"); 650 | } 651 | } 652 | 653 | badlyNamedUnion :union $Cxx.name("renamedUnion") { 654 | badlyNamedGroup :group $Cxx.name("renamedGroup") { 655 | foo @3 :Void; 656 | bar @4 :Void; 657 | } 658 | baz @5 :NestedStruct $Cxx.name("qux"); 659 | } 660 | } 661 | 662 | -------------------------------------------------------------------------------- /compiler/schema.capnp.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPN_A93FC509624C72D9 2 | #define CAPN_A93FC509624C72D9 3 | /* AUTO GENERATED - DO NOT EDIT */ 4 | #include 5 | 6 | #if CAPN_VERSION != 1 7 | #error "version mismatch between capnp_c.h and generated code" 8 | #endif 9 | 10 | #ifndef capnp_nowarn 11 | # ifdef __GNUC__ 12 | # define capnp_nowarn __extension__ 13 | # else 14 | # define capnp_nowarn 15 | # endif 16 | #endif 17 | 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | struct Node; 24 | struct Node_Parameter; 25 | struct Node_NestedNode; 26 | struct Field; 27 | struct Enumerant; 28 | struct Superclass; 29 | struct Method; 30 | struct Type; 31 | struct Brand; 32 | struct Brand_Scope; 33 | struct Brand_Binding; 34 | struct Value; 35 | struct Annotation; 36 | struct CodeGeneratorRequest; 37 | struct CodeGeneratorRequest_RequestedFile; 38 | struct CodeGeneratorRequest_RequestedFile_Import; 39 | 40 | typedef struct {capn_ptr p;} Node_ptr; 41 | typedef struct {capn_ptr p;} Node_Parameter_ptr; 42 | typedef struct {capn_ptr p;} Node_NestedNode_ptr; 43 | typedef struct {capn_ptr p;} Field_ptr; 44 | typedef struct {capn_ptr p;} Enumerant_ptr; 45 | typedef struct {capn_ptr p;} Superclass_ptr; 46 | typedef struct {capn_ptr p;} Method_ptr; 47 | typedef struct {capn_ptr p;} Type_ptr; 48 | typedef struct {capn_ptr p;} Brand_ptr; 49 | typedef struct {capn_ptr p;} Brand_Scope_ptr; 50 | typedef struct {capn_ptr p;} Brand_Binding_ptr; 51 | typedef struct {capn_ptr p;} Value_ptr; 52 | typedef struct {capn_ptr p;} Annotation_ptr; 53 | typedef struct {capn_ptr p;} CodeGeneratorRequest_ptr; 54 | typedef struct {capn_ptr p;} CodeGeneratorRequest_RequestedFile_ptr; 55 | typedef struct {capn_ptr p;} CodeGeneratorRequest_RequestedFile_Import_ptr; 56 | 57 | typedef struct {capn_ptr p;} Node_list; 58 | typedef struct {capn_ptr p;} Node_Parameter_list; 59 | typedef struct {capn_ptr p;} Node_NestedNode_list; 60 | typedef struct {capn_ptr p;} Field_list; 61 | typedef struct {capn_ptr p;} Enumerant_list; 62 | typedef struct {capn_ptr p;} Superclass_list; 63 | typedef struct {capn_ptr p;} Method_list; 64 | typedef struct {capn_ptr p;} Type_list; 65 | typedef struct {capn_ptr p;} Brand_list; 66 | typedef struct {capn_ptr p;} Brand_Scope_list; 67 | typedef struct {capn_ptr p;} Brand_Binding_list; 68 | typedef struct {capn_ptr p;} Value_list; 69 | typedef struct {capn_ptr p;} Annotation_list; 70 | typedef struct {capn_ptr p;} CodeGeneratorRequest_list; 71 | typedef struct {capn_ptr p;} CodeGeneratorRequest_RequestedFile_list; 72 | typedef struct {capn_ptr p;} CodeGeneratorRequest_RequestedFile_Import_list; 73 | 74 | enum ElementSize { 75 | ElementSize_empty = 0, 76 | ElementSize_bit = 1, 77 | ElementSize_byte = 2, 78 | ElementSize_twoBytes = 3, 79 | ElementSize_fourBytes = 4, 80 | ElementSize_eightBytes = 5, 81 | ElementSize_pointer = 6, 82 | ElementSize_inlineComposite = 7 83 | }; 84 | extern uint16_t Field_noDiscriminant; 85 | enum Node_which { 86 | Node_file = 0, 87 | Node__struct = 1, 88 | Node__enum = 2, 89 | Node__interface = 3, 90 | Node__const = 4, 91 | Node_annotation = 5 92 | }; 93 | 94 | struct Node { 95 | uint64_t id; 96 | capn_text displayName; 97 | uint32_t displayNamePrefixLength; 98 | uint64_t scopeId; 99 | Node_Parameter_list parameters; 100 | unsigned isGeneric : 1; 101 | Node_NestedNode_list nestedNodes; 102 | Annotation_list annotations; 103 | enum Node_which which; 104 | capnp_nowarn union { 105 | capnp_nowarn struct { 106 | uint16_t dataWordCount; 107 | uint16_t pointerCount; 108 | enum ElementSize preferredListEncoding; 109 | unsigned isGroup : 1; 110 | uint16_t discriminantCount; 111 | uint32_t discriminantOffset; 112 | Field_list fields; 113 | } _struct; 114 | capnp_nowarn struct { 115 | Enumerant_list enumerants; 116 | } _enum; 117 | capnp_nowarn struct { 118 | Method_list methods; 119 | Superclass_list superclasses; 120 | } _interface; 121 | capnp_nowarn struct { 122 | Type_ptr type; 123 | Value_ptr value; 124 | } _const; 125 | capnp_nowarn struct { 126 | Type_ptr type; 127 | unsigned targetsFile : 1; 128 | unsigned targetsConst : 1; 129 | unsigned targetsEnum : 1; 130 | unsigned targetsEnumerant : 1; 131 | unsigned targetsStruct : 1; 132 | unsigned targetsField : 1; 133 | unsigned targetsUnion : 1; 134 | unsigned targetsGroup : 1; 135 | unsigned targetsInterface : 1; 136 | unsigned targetsMethod : 1; 137 | unsigned targetsParam : 1; 138 | unsigned targetsAnnotation : 1; 139 | } annotation; 140 | }; 141 | }; 142 | 143 | static const size_t Node_word_count = 5; 144 | 145 | static const size_t Node_pointer_count = 6; 146 | 147 | static const size_t Node_struct_bytes_count = 88; 148 | 149 | 150 | uint64_t Node_get_id(Node_ptr p); 151 | 152 | capn_text Node_get_displayName(Node_ptr p); 153 | 154 | uint32_t Node_get_displayNamePrefixLength(Node_ptr p); 155 | 156 | uint64_t Node_get_scopeId(Node_ptr p); 157 | 158 | Node_Parameter_list Node_get_parameters(Node_ptr p); 159 | 160 | unsigned Node_get_isGeneric(Node_ptr p); 161 | 162 | Node_NestedNode_list Node_get_nestedNodes(Node_ptr p); 163 | 164 | Annotation_list Node_get_annotations(Node_ptr p); 165 | 166 | void Node_set_id(Node_ptr p, uint64_t id); 167 | 168 | void Node_set_displayName(Node_ptr p, capn_text displayName); 169 | 170 | void Node_set_displayNamePrefixLength(Node_ptr p, uint32_t displayNamePrefixLength); 171 | 172 | void Node_set_scopeId(Node_ptr p, uint64_t scopeId); 173 | 174 | void Node_set_parameters(Node_ptr p, Node_Parameter_list parameters); 175 | 176 | void Node_set_isGeneric(Node_ptr p, unsigned isGeneric); 177 | 178 | void Node_set_nestedNodes(Node_ptr p, Node_NestedNode_list nestedNodes); 179 | 180 | void Node_set_annotations(Node_ptr p, Annotation_list annotations); 181 | 182 | struct Node_Parameter { 183 | capn_text name; 184 | }; 185 | 186 | static const size_t Node_Parameter_word_count = 0; 187 | 188 | static const size_t Node_Parameter_pointer_count = 1; 189 | 190 | static const size_t Node_Parameter_struct_bytes_count = 8; 191 | 192 | 193 | capn_text Node_Parameter_get_name(Node_Parameter_ptr p); 194 | 195 | void Node_Parameter_set_name(Node_Parameter_ptr p, capn_text name); 196 | 197 | struct Node_NestedNode { 198 | capn_text name; 199 | uint64_t id; 200 | }; 201 | 202 | static const size_t Node_NestedNode_word_count = 1; 203 | 204 | static const size_t Node_NestedNode_pointer_count = 1; 205 | 206 | static const size_t Node_NestedNode_struct_bytes_count = 16; 207 | 208 | 209 | capn_text Node_NestedNode_get_name(Node_NestedNode_ptr p); 210 | 211 | uint64_t Node_NestedNode_get_id(Node_NestedNode_ptr p); 212 | 213 | void Node_NestedNode_set_name(Node_NestedNode_ptr p, capn_text name); 214 | 215 | void Node_NestedNode_set_id(Node_NestedNode_ptr p, uint64_t id); 216 | enum Field_which { 217 | Field_slot = 0, 218 | Field_group = 1 219 | }; 220 | enum Field_ordinal_which { 221 | Field_ordinal_implicit = 0, 222 | Field_ordinal__explicit = 1 223 | }; 224 | 225 | struct Field { 226 | capn_text name; 227 | uint16_t codeOrder; 228 | Annotation_list annotations; 229 | uint16_t discriminantValue; 230 | enum Field_which which; 231 | capnp_nowarn union { 232 | capnp_nowarn struct { 233 | uint32_t offset; 234 | Type_ptr type; 235 | Value_ptr defaultValue; 236 | unsigned hadExplicitDefault : 1; 237 | } slot; 238 | capnp_nowarn struct { 239 | uint64_t typeId; 240 | } group; 241 | }; 242 | enum Field_ordinal_which ordinal_which; 243 | capnp_nowarn union { 244 | uint16_t _explicit; 245 | } ordinal; 246 | }; 247 | 248 | static const size_t Field_word_count = 3; 249 | 250 | static const size_t Field_pointer_count = 4; 251 | 252 | static const size_t Field_struct_bytes_count = 56; 253 | 254 | 255 | capn_text Field_get_name(Field_ptr p); 256 | 257 | uint16_t Field_get_codeOrder(Field_ptr p); 258 | 259 | Annotation_list Field_get_annotations(Field_ptr p); 260 | 261 | uint16_t Field_get_discriminantValue(Field_ptr p); 262 | 263 | void Field_set_name(Field_ptr p, capn_text name); 264 | 265 | void Field_set_codeOrder(Field_ptr p, uint16_t codeOrder); 266 | 267 | void Field_set_annotations(Field_ptr p, Annotation_list annotations); 268 | 269 | void Field_set_discriminantValue(Field_ptr p, uint16_t discriminantValue); 270 | 271 | struct Enumerant { 272 | capn_text name; 273 | uint16_t codeOrder; 274 | Annotation_list annotations; 275 | }; 276 | 277 | static const size_t Enumerant_word_count = 1; 278 | 279 | static const size_t Enumerant_pointer_count = 2; 280 | 281 | static const size_t Enumerant_struct_bytes_count = 24; 282 | 283 | 284 | capn_text Enumerant_get_name(Enumerant_ptr p); 285 | 286 | uint16_t Enumerant_get_codeOrder(Enumerant_ptr p); 287 | 288 | Annotation_list Enumerant_get_annotations(Enumerant_ptr p); 289 | 290 | void Enumerant_set_name(Enumerant_ptr p, capn_text name); 291 | 292 | void Enumerant_set_codeOrder(Enumerant_ptr p, uint16_t codeOrder); 293 | 294 | void Enumerant_set_annotations(Enumerant_ptr p, Annotation_list annotations); 295 | 296 | struct Superclass { 297 | uint64_t id; 298 | Brand_ptr brand; 299 | }; 300 | 301 | static const size_t Superclass_word_count = 1; 302 | 303 | static const size_t Superclass_pointer_count = 1; 304 | 305 | static const size_t Superclass_struct_bytes_count = 16; 306 | 307 | 308 | uint64_t Superclass_get_id(Superclass_ptr p); 309 | 310 | Brand_ptr Superclass_get_brand(Superclass_ptr p); 311 | 312 | void Superclass_set_id(Superclass_ptr p, uint64_t id); 313 | 314 | void Superclass_set_brand(Superclass_ptr p, Brand_ptr brand); 315 | 316 | struct Method { 317 | capn_text name; 318 | uint16_t codeOrder; 319 | Node_Parameter_list implicitParameters; 320 | uint64_t paramStructType; 321 | Brand_ptr paramBrand; 322 | uint64_t resultStructType; 323 | Brand_ptr resultBrand; 324 | Annotation_list annotations; 325 | }; 326 | 327 | static const size_t Method_word_count = 3; 328 | 329 | static const size_t Method_pointer_count = 5; 330 | 331 | static const size_t Method_struct_bytes_count = 64; 332 | 333 | 334 | capn_text Method_get_name(Method_ptr p); 335 | 336 | uint16_t Method_get_codeOrder(Method_ptr p); 337 | 338 | Node_Parameter_list Method_get_implicitParameters(Method_ptr p); 339 | 340 | uint64_t Method_get_paramStructType(Method_ptr p); 341 | 342 | Brand_ptr Method_get_paramBrand(Method_ptr p); 343 | 344 | uint64_t Method_get_resultStructType(Method_ptr p); 345 | 346 | Brand_ptr Method_get_resultBrand(Method_ptr p); 347 | 348 | Annotation_list Method_get_annotations(Method_ptr p); 349 | 350 | void Method_set_name(Method_ptr p, capn_text name); 351 | 352 | void Method_set_codeOrder(Method_ptr p, uint16_t codeOrder); 353 | 354 | void Method_set_implicitParameters(Method_ptr p, Node_Parameter_list implicitParameters); 355 | 356 | void Method_set_paramStructType(Method_ptr p, uint64_t paramStructType); 357 | 358 | void Method_set_paramBrand(Method_ptr p, Brand_ptr paramBrand); 359 | 360 | void Method_set_resultStructType(Method_ptr p, uint64_t resultStructType); 361 | 362 | void Method_set_resultBrand(Method_ptr p, Brand_ptr resultBrand); 363 | 364 | void Method_set_annotations(Method_ptr p, Annotation_list annotations); 365 | enum Type_anyPointer_which { 366 | Type_anyPointer_unconstrained = 0, 367 | Type_anyPointer_parameter = 1, 368 | Type_anyPointer_implicitMethodParameter = 2 369 | }; 370 | enum Type_which { 371 | Type__void = 0, 372 | Type__bool = 1, 373 | Type_int8 = 2, 374 | Type_int16 = 3, 375 | Type_int32 = 4, 376 | Type_int64 = 5, 377 | Type_uint8 = 6, 378 | Type_uint16 = 7, 379 | Type_uint32 = 8, 380 | Type_uint64 = 9, 381 | Type_float32 = 10, 382 | Type_float64 = 11, 383 | Type_text = 12, 384 | Type_data = 13, 385 | Type__list = 14, 386 | Type__enum = 15, 387 | Type__struct = 16, 388 | Type__interface = 17, 389 | Type_anyPointer = 18 390 | }; 391 | 392 | struct Type { 393 | enum Type_which which; 394 | capnp_nowarn union { 395 | capnp_nowarn struct { 396 | Type_ptr elementType; 397 | } _list; 398 | capnp_nowarn struct { 399 | uint64_t typeId; 400 | Brand_ptr brand; 401 | } _enum; 402 | capnp_nowarn struct { 403 | uint64_t typeId; 404 | Brand_ptr brand; 405 | } _struct; 406 | capnp_nowarn struct { 407 | uint64_t typeId; 408 | Brand_ptr brand; 409 | } _interface; 410 | capnp_nowarn struct { 411 | enum Type_anyPointer_which which; 412 | capnp_nowarn union { 413 | capnp_nowarn struct { 414 | uint64_t scopeId; 415 | uint16_t parameterIndex; 416 | } parameter; 417 | capnp_nowarn struct { 418 | uint16_t parameterIndex; 419 | } implicitMethodParameter; 420 | }; 421 | } anyPointer; 422 | }; 423 | }; 424 | 425 | static const size_t Type_word_count = 3; 426 | 427 | static const size_t Type_pointer_count = 1; 428 | 429 | static const size_t Type_struct_bytes_count = 32; 430 | 431 | 432 | struct Brand { 433 | Brand_Scope_list scopes; 434 | }; 435 | 436 | static const size_t Brand_word_count = 0; 437 | 438 | static const size_t Brand_pointer_count = 1; 439 | 440 | static const size_t Brand_struct_bytes_count = 8; 441 | 442 | 443 | Brand_Scope_list Brand_get_scopes(Brand_ptr p); 444 | 445 | void Brand_set_scopes(Brand_ptr p, Brand_Scope_list scopes); 446 | enum Brand_Scope_which { 447 | Brand_Scope_bind = 0, 448 | Brand_Scope_inherit = 1 449 | }; 450 | 451 | struct Brand_Scope { 452 | uint64_t scopeId; 453 | enum Brand_Scope_which which; 454 | capnp_nowarn union { 455 | Brand_Binding_list bind; 456 | }; 457 | }; 458 | 459 | static const size_t Brand_Scope_word_count = 2; 460 | 461 | static const size_t Brand_Scope_pointer_count = 1; 462 | 463 | static const size_t Brand_Scope_struct_bytes_count = 24; 464 | 465 | 466 | uint64_t Brand_Scope_get_scopeId(Brand_Scope_ptr p); 467 | 468 | void Brand_Scope_set_scopeId(Brand_Scope_ptr p, uint64_t scopeId); 469 | enum Brand_Binding_which { 470 | Brand_Binding_unbound = 0, 471 | Brand_Binding_type = 1 472 | }; 473 | 474 | struct Brand_Binding { 475 | enum Brand_Binding_which which; 476 | capnp_nowarn union { 477 | Type_ptr type; 478 | }; 479 | }; 480 | 481 | static const size_t Brand_Binding_word_count = 1; 482 | 483 | static const size_t Brand_Binding_pointer_count = 1; 484 | 485 | static const size_t Brand_Binding_struct_bytes_count = 16; 486 | 487 | enum Value_which { 488 | Value__void = 0, 489 | Value__bool = 1, 490 | Value_int8 = 2, 491 | Value_int16 = 3, 492 | Value_int32 = 4, 493 | Value_int64 = 5, 494 | Value_uint8 = 6, 495 | Value_uint16 = 7, 496 | Value_uint32 = 8, 497 | Value_uint64 = 9, 498 | Value_float32 = 10, 499 | Value_float64 = 11, 500 | Value_text = 12, 501 | Value_data = 13, 502 | Value__list = 14, 503 | Value__enum = 15, 504 | Value__struct = 16, 505 | Value__interface = 17, 506 | Value_anyPointer = 18 507 | }; 508 | 509 | struct Value { 510 | enum Value_which which; 511 | capnp_nowarn union { 512 | unsigned _bool : 1; 513 | int8_t int8; 514 | int16_t int16; 515 | int32_t int32; 516 | int64_t int64; 517 | uint8_t uint8; 518 | uint16_t uint16; 519 | uint32_t uint32; 520 | uint64_t uint64; 521 | float float32; 522 | double float64; 523 | capn_text text; 524 | capn_data data; 525 | capn_ptr _list; 526 | uint16_t _enum; 527 | capn_ptr _struct; 528 | capn_ptr anyPointer; 529 | }; 530 | }; 531 | 532 | static const size_t Value_word_count = 2; 533 | 534 | static const size_t Value_pointer_count = 1; 535 | 536 | static const size_t Value_struct_bytes_count = 24; 537 | 538 | 539 | struct Annotation { 540 | uint64_t id; 541 | Brand_ptr brand; 542 | Value_ptr value; 543 | }; 544 | 545 | static const size_t Annotation_word_count = 1; 546 | 547 | static const size_t Annotation_pointer_count = 2; 548 | 549 | static const size_t Annotation_struct_bytes_count = 24; 550 | 551 | 552 | uint64_t Annotation_get_id(Annotation_ptr p); 553 | 554 | Brand_ptr Annotation_get_brand(Annotation_ptr p); 555 | 556 | Value_ptr Annotation_get_value(Annotation_ptr p); 557 | 558 | void Annotation_set_id(Annotation_ptr p, uint64_t id); 559 | 560 | void Annotation_set_brand(Annotation_ptr p, Brand_ptr brand); 561 | 562 | void Annotation_set_value(Annotation_ptr p, Value_ptr value); 563 | 564 | struct CodeGeneratorRequest { 565 | Node_list nodes; 566 | CodeGeneratorRequest_RequestedFile_list requestedFiles; 567 | }; 568 | 569 | static const size_t CodeGeneratorRequest_word_count = 0; 570 | 571 | static const size_t CodeGeneratorRequest_pointer_count = 2; 572 | 573 | static const size_t CodeGeneratorRequest_struct_bytes_count = 16; 574 | 575 | 576 | Node_list CodeGeneratorRequest_get_nodes(CodeGeneratorRequest_ptr p); 577 | 578 | CodeGeneratorRequest_RequestedFile_list CodeGeneratorRequest_get_requestedFiles(CodeGeneratorRequest_ptr p); 579 | 580 | void CodeGeneratorRequest_set_nodes(CodeGeneratorRequest_ptr p, Node_list nodes); 581 | 582 | void CodeGeneratorRequest_set_requestedFiles(CodeGeneratorRequest_ptr p, CodeGeneratorRequest_RequestedFile_list requestedFiles); 583 | 584 | struct CodeGeneratorRequest_RequestedFile { 585 | uint64_t id; 586 | capn_text filename; 587 | CodeGeneratorRequest_RequestedFile_Import_list imports; 588 | }; 589 | 590 | static const size_t CodeGeneratorRequest_RequestedFile_word_count = 1; 591 | 592 | static const size_t CodeGeneratorRequest_RequestedFile_pointer_count = 2; 593 | 594 | static const size_t CodeGeneratorRequest_RequestedFile_struct_bytes_count = 24; 595 | 596 | 597 | uint64_t CodeGeneratorRequest_RequestedFile_get_id(CodeGeneratorRequest_RequestedFile_ptr p); 598 | 599 | capn_text CodeGeneratorRequest_RequestedFile_get_filename(CodeGeneratorRequest_RequestedFile_ptr p); 600 | 601 | CodeGeneratorRequest_RequestedFile_Import_list CodeGeneratorRequest_RequestedFile_get_imports(CodeGeneratorRequest_RequestedFile_ptr p); 602 | 603 | void CodeGeneratorRequest_RequestedFile_set_id(CodeGeneratorRequest_RequestedFile_ptr p, uint64_t id); 604 | 605 | void CodeGeneratorRequest_RequestedFile_set_filename(CodeGeneratorRequest_RequestedFile_ptr p, capn_text filename); 606 | 607 | void CodeGeneratorRequest_RequestedFile_set_imports(CodeGeneratorRequest_RequestedFile_ptr p, CodeGeneratorRequest_RequestedFile_Import_list imports); 608 | 609 | struct CodeGeneratorRequest_RequestedFile_Import { 610 | uint64_t id; 611 | capn_text name; 612 | }; 613 | 614 | static const size_t CodeGeneratorRequest_RequestedFile_Import_word_count = 1; 615 | 616 | static const size_t CodeGeneratorRequest_RequestedFile_Import_pointer_count = 1; 617 | 618 | static const size_t CodeGeneratorRequest_RequestedFile_Import_struct_bytes_count = 16; 619 | 620 | 621 | uint64_t CodeGeneratorRequest_RequestedFile_Import_get_id(CodeGeneratorRequest_RequestedFile_Import_ptr p); 622 | 623 | capn_text CodeGeneratorRequest_RequestedFile_Import_get_name(CodeGeneratorRequest_RequestedFile_Import_ptr p); 624 | 625 | void CodeGeneratorRequest_RequestedFile_Import_set_id(CodeGeneratorRequest_RequestedFile_Import_ptr p, uint64_t id); 626 | 627 | void CodeGeneratorRequest_RequestedFile_Import_set_name(CodeGeneratorRequest_RequestedFile_Import_ptr p, capn_text name); 628 | 629 | Node_ptr new_Node(struct capn_segment*); 630 | Node_Parameter_ptr new_Node_Parameter(struct capn_segment*); 631 | Node_NestedNode_ptr new_Node_NestedNode(struct capn_segment*); 632 | Field_ptr new_Field(struct capn_segment*); 633 | Enumerant_ptr new_Enumerant(struct capn_segment*); 634 | Superclass_ptr new_Superclass(struct capn_segment*); 635 | Method_ptr new_Method(struct capn_segment*); 636 | Type_ptr new_Type(struct capn_segment*); 637 | Brand_ptr new_Brand(struct capn_segment*); 638 | Brand_Scope_ptr new_Brand_Scope(struct capn_segment*); 639 | Brand_Binding_ptr new_Brand_Binding(struct capn_segment*); 640 | Value_ptr new_Value(struct capn_segment*); 641 | Annotation_ptr new_Annotation(struct capn_segment*); 642 | CodeGeneratorRequest_ptr new_CodeGeneratorRequest(struct capn_segment*); 643 | CodeGeneratorRequest_RequestedFile_ptr new_CodeGeneratorRequest_RequestedFile(struct capn_segment*); 644 | CodeGeneratorRequest_RequestedFile_Import_ptr new_CodeGeneratorRequest_RequestedFile_Import(struct capn_segment*); 645 | 646 | Node_list new_Node_list(struct capn_segment*, int len); 647 | Node_Parameter_list new_Node_Parameter_list(struct capn_segment*, int len); 648 | Node_NestedNode_list new_Node_NestedNode_list(struct capn_segment*, int len); 649 | Field_list new_Field_list(struct capn_segment*, int len); 650 | Enumerant_list new_Enumerant_list(struct capn_segment*, int len); 651 | Superclass_list new_Superclass_list(struct capn_segment*, int len); 652 | Method_list new_Method_list(struct capn_segment*, int len); 653 | Type_list new_Type_list(struct capn_segment*, int len); 654 | Brand_list new_Brand_list(struct capn_segment*, int len); 655 | Brand_Scope_list new_Brand_Scope_list(struct capn_segment*, int len); 656 | Brand_Binding_list new_Brand_Binding_list(struct capn_segment*, int len); 657 | Value_list new_Value_list(struct capn_segment*, int len); 658 | Annotation_list new_Annotation_list(struct capn_segment*, int len); 659 | CodeGeneratorRequest_list new_CodeGeneratorRequest_list(struct capn_segment*, int len); 660 | CodeGeneratorRequest_RequestedFile_list new_CodeGeneratorRequest_RequestedFile_list(struct capn_segment*, int len); 661 | CodeGeneratorRequest_RequestedFile_Import_list new_CodeGeneratorRequest_RequestedFile_Import_list(struct capn_segment*, int len); 662 | 663 | void read_Node(struct Node*, Node_ptr); 664 | void read_Node_Parameter(struct Node_Parameter*, Node_Parameter_ptr); 665 | void read_Node_NestedNode(struct Node_NestedNode*, Node_NestedNode_ptr); 666 | void read_Field(struct Field*, Field_ptr); 667 | void read_Enumerant(struct Enumerant*, Enumerant_ptr); 668 | void read_Superclass(struct Superclass*, Superclass_ptr); 669 | void read_Method(struct Method*, Method_ptr); 670 | void read_Type(struct Type*, Type_ptr); 671 | void read_Brand(struct Brand*, Brand_ptr); 672 | void read_Brand_Scope(struct Brand_Scope*, Brand_Scope_ptr); 673 | void read_Brand_Binding(struct Brand_Binding*, Brand_Binding_ptr); 674 | void read_Value(struct Value*, Value_ptr); 675 | void read_Annotation(struct Annotation*, Annotation_ptr); 676 | void read_CodeGeneratorRequest(struct CodeGeneratorRequest*, CodeGeneratorRequest_ptr); 677 | void read_CodeGeneratorRequest_RequestedFile(struct CodeGeneratorRequest_RequestedFile*, CodeGeneratorRequest_RequestedFile_ptr); 678 | void read_CodeGeneratorRequest_RequestedFile_Import(struct CodeGeneratorRequest_RequestedFile_Import*, CodeGeneratorRequest_RequestedFile_Import_ptr); 679 | 680 | void write_Node(const struct Node*, Node_ptr); 681 | void write_Node_Parameter(const struct Node_Parameter*, Node_Parameter_ptr); 682 | void write_Node_NestedNode(const struct Node_NestedNode*, Node_NestedNode_ptr); 683 | void write_Field(const struct Field*, Field_ptr); 684 | void write_Enumerant(const struct Enumerant*, Enumerant_ptr); 685 | void write_Superclass(const struct Superclass*, Superclass_ptr); 686 | void write_Method(const struct Method*, Method_ptr); 687 | void write_Type(const struct Type*, Type_ptr); 688 | void write_Brand(const struct Brand*, Brand_ptr); 689 | void write_Brand_Scope(const struct Brand_Scope*, Brand_Scope_ptr); 690 | void write_Brand_Binding(const struct Brand_Binding*, Brand_Binding_ptr); 691 | void write_Value(const struct Value*, Value_ptr); 692 | void write_Annotation(const struct Annotation*, Annotation_ptr); 693 | void write_CodeGeneratorRequest(const struct CodeGeneratorRequest*, CodeGeneratorRequest_ptr); 694 | void write_CodeGeneratorRequest_RequestedFile(const struct CodeGeneratorRequest_RequestedFile*, CodeGeneratorRequest_RequestedFile_ptr); 695 | void write_CodeGeneratorRequest_RequestedFile_Import(const struct CodeGeneratorRequest_RequestedFile_Import*, CodeGeneratorRequest_RequestedFile_Import_ptr); 696 | 697 | void get_Node(struct Node*, Node_list, int i); 698 | void get_Node_Parameter(struct Node_Parameter*, Node_Parameter_list, int i); 699 | void get_Node_NestedNode(struct Node_NestedNode*, Node_NestedNode_list, int i); 700 | void get_Field(struct Field*, Field_list, int i); 701 | void get_Enumerant(struct Enumerant*, Enumerant_list, int i); 702 | void get_Superclass(struct Superclass*, Superclass_list, int i); 703 | void get_Method(struct Method*, Method_list, int i); 704 | void get_Type(struct Type*, Type_list, int i); 705 | void get_Brand(struct Brand*, Brand_list, int i); 706 | void get_Brand_Scope(struct Brand_Scope*, Brand_Scope_list, int i); 707 | void get_Brand_Binding(struct Brand_Binding*, Brand_Binding_list, int i); 708 | void get_Value(struct Value*, Value_list, int i); 709 | void get_Annotation(struct Annotation*, Annotation_list, int i); 710 | void get_CodeGeneratorRequest(struct CodeGeneratorRequest*, CodeGeneratorRequest_list, int i); 711 | void get_CodeGeneratorRequest_RequestedFile(struct CodeGeneratorRequest_RequestedFile*, CodeGeneratorRequest_RequestedFile_list, int i); 712 | void get_CodeGeneratorRequest_RequestedFile_Import(struct CodeGeneratorRequest_RequestedFile_Import*, CodeGeneratorRequest_RequestedFile_Import_list, int i); 713 | 714 | void set_Node(const struct Node*, Node_list, int i); 715 | void set_Node_Parameter(const struct Node_Parameter*, Node_Parameter_list, int i); 716 | void set_Node_NestedNode(const struct Node_NestedNode*, Node_NestedNode_list, int i); 717 | void set_Field(const struct Field*, Field_list, int i); 718 | void set_Enumerant(const struct Enumerant*, Enumerant_list, int i); 719 | void set_Superclass(const struct Superclass*, Superclass_list, int i); 720 | void set_Method(const struct Method*, Method_list, int i); 721 | void set_Type(const struct Type*, Type_list, int i); 722 | void set_Brand(const struct Brand*, Brand_list, int i); 723 | void set_Brand_Scope(const struct Brand_Scope*, Brand_Scope_list, int i); 724 | void set_Brand_Binding(const struct Brand_Binding*, Brand_Binding_list, int i); 725 | void set_Value(const struct Value*, Value_list, int i); 726 | void set_Annotation(const struct Annotation*, Annotation_list, int i); 727 | void set_CodeGeneratorRequest(const struct CodeGeneratorRequest*, CodeGeneratorRequest_list, int i); 728 | void set_CodeGeneratorRequest_RequestedFile(const struct CodeGeneratorRequest_RequestedFile*, CodeGeneratorRequest_RequestedFile_list, int i); 729 | void set_CodeGeneratorRequest_RequestedFile_Import(const struct CodeGeneratorRequest_RequestedFile_Import*, CodeGeneratorRequest_RequestedFile_Import_list, int i); 730 | 731 | #ifdef __cplusplus 732 | } 733 | #endif 734 | #endif 735 | -------------------------------------------------------------------------------- /lib/capn.c: -------------------------------------------------------------------------------- 1 | /* vim: set sw=8 ts=8 sts=8 noet: */ 2 | /* capn.c 3 | * 4 | * Copyright (C) 2013 James McKaskill 5 | * 6 | * This software may be modified and distributed under the terms 7 | * of the MIT license. See the LICENSE file for details. 8 | */ 9 | 10 | #ifdef __GNUC__ 11 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 12 | #endif 13 | 14 | #include "capnp_c.h" 15 | 16 | #include 17 | #include 18 | #ifndef _MSC_VER 19 | #include 20 | #endif 21 | 22 | #define STRUCT_PTR 0 23 | #define LIST_PTR 1 24 | #define FAR_PTR 2 25 | #define DOUBLE_PTR 6 26 | 27 | #define VOID_LIST 0 28 | #define BIT_1_LIST 1 29 | #define BYTE_1_LIST 2 30 | #define BYTE_2_LIST 3 31 | #define BYTE_4_LIST 4 32 | #define BYTE_8_LIST 5 33 | #define PTR_LIST 6 34 | #define COMPOSITE_LIST 7 35 | 36 | #define U64(val) ((uint64_t) (val)) 37 | #define I64(val) ((int64_t) (val)) 38 | #define U32(val) ((uint32_t) (val)) 39 | #define I32(val) ((int32_t) (val)) 40 | #define U16(val) ((uint16_t) (val)) 41 | #define I16(val) ((int16_t) (val)) 42 | 43 | #ifndef min 44 | static int min(int a, int b) { return (a < b) ? a : b; } 45 | #endif 46 | 47 | #ifdef BYTE_ORDER 48 | #define CAPN_LITTLE (BYTE_ORDER == LITTLE_ENDIAN) 49 | #elif defined(__BYTE_ORDER) 50 | #define CAPN_LITTLE (__BYTE_ORDER == __LITTLE_ENDIAN) 51 | #else 52 | #define CAPN_LITTLE 0 53 | #endif 54 | 55 | struct capn_tree *capn_tree_insert(struct capn_tree *root, struct capn_tree *n) { 56 | n->red = 1; 57 | n->link[0] = n->link[1] = NULL; 58 | 59 | for (;;) { 60 | /* parent, uncle, grandparent, great grandparent link */ 61 | struct capn_tree *p, *u, *g, **gglink; 62 | int dir; 63 | 64 | /* Case 1: N is root */ 65 | p = n->parent; 66 | if (!p) { 67 | n->red = 0; 68 | root = n; 69 | break; 70 | } 71 | 72 | /* Case 2: p is black */ 73 | if (!p->red) { 74 | break; 75 | } 76 | 77 | g = p->parent; 78 | dir = (p == g->link[1]); 79 | 80 | /* Case 3: P and U are red, switch g to red, but must 81 | * loop as G could be root or have a red parent 82 | * g to G 83 | * / \ / \ 84 | * P U p u 85 | * / / 86 | * N N 87 | */ 88 | u = g->link[!dir]; 89 | if (u != NULL && u->red) { 90 | p->red = 0; 91 | u->red = 0; 92 | g->red = 1; 93 | n = g; 94 | continue; 95 | } 96 | 97 | if (!g->parent) { 98 | gglink = &root; 99 | } else if (g->parent->link[1] == g) { 100 | gglink = &g->parent->link[1]; 101 | } else { 102 | gglink = &g->parent->link[0]; 103 | } 104 | 105 | if (dir != (n == p->link[1])) { 106 | /* Case 4: rotate on P, then on g 107 | * here dir is / 108 | * g to g to n 109 | * / \ / \ / \ 110 | * P u N u P G 111 | * / \ / \ /| / \ 112 | * 1 N P 3 1 2 3 u 113 | * / \ / \ 114 | * 2 3 1 2 115 | */ 116 | struct capn_tree *two = n->link[dir]; 117 | struct capn_tree *three = n->link[!dir]; 118 | p->link[!dir] = two; 119 | g->link[dir] = three; 120 | n->link[dir] = p; 121 | n->link[!dir] = g; 122 | *gglink = n; 123 | n->parent = g->parent; 124 | p->parent = n; 125 | g->parent = n; 126 | if (two) 127 | two->parent = p; 128 | if (three) 129 | three->parent = g; 130 | n->red = 0; 131 | g->red = 1; 132 | } else { 133 | /* Case 5: rotate on g 134 | * here dir is / 135 | * g to p 136 | * / \ / \ 137 | * P u N G 138 | * / \ /| / \ 139 | * N 3 1 2 3 u 140 | * / \ 141 | * 1 2 142 | */ 143 | struct capn_tree *three = p->link[!dir]; 144 | g->link[dir] = three; 145 | p->link[!dir] = g; 146 | *gglink = p; 147 | p->parent = g->parent; 148 | g->parent = p; 149 | if (three) 150 | three->parent = g; 151 | g->red = 1; 152 | p->red = 0; 153 | } 154 | 155 | break; 156 | } 157 | 158 | return root; 159 | } 160 | 161 | void capn_append_segment(struct capn *c, struct capn_segment *s) { 162 | s->id = c->segnum++; 163 | s->capn = c; 164 | s->next = NULL; 165 | 166 | if (c->lastseg) { 167 | c->lastseg->next = s; 168 | c->lastseg->hdr.link[1] = &s->hdr; 169 | s->hdr.parent = &c->lastseg->hdr; 170 | } else { 171 | c->seglist = s; 172 | s->hdr.parent = NULL; 173 | } 174 | 175 | c->lastseg = s; 176 | c->segtree = capn_tree_insert(c->segtree, &s->hdr); 177 | } 178 | 179 | static char *new_data(struct capn *c, int sz, struct capn_segment **ps) { 180 | struct capn_segment *s; 181 | 182 | /* find a segment with sufficient data */ 183 | for (s = c->seglist; s != NULL; s = s->next) { 184 | if (s->len + sz <= s->cap) { 185 | goto end; 186 | } 187 | } 188 | 189 | s = c->create ? c->create(c->user, c->segnum, sz) : NULL; 190 | if (!s) { 191 | *ps = NULL; 192 | return NULL; 193 | } 194 | 195 | capn_append_segment(c, s); 196 | end: 197 | *ps = s; 198 | s->len += sz; 199 | return s->data + s->len - sz; 200 | } 201 | 202 | static struct capn_segment *lookup_segment(struct capn* c, struct capn_segment *s, uint32_t id) { 203 | struct capn_tree **x; 204 | struct capn_segment *y = NULL; 205 | 206 | if (s && s->id == id) 207 | return s; 208 | if (!c) 209 | return NULL; 210 | 211 | if (id < c->segnum) { 212 | x = &c->segtree; 213 | while (*x) { 214 | y = (struct capn_segment*) *x; 215 | if (id == y->id) { 216 | return y; 217 | } else if (id < y->id) { 218 | x = &y->hdr.link[0]; 219 | } else { 220 | x = &y->hdr.link[1]; 221 | } 222 | } 223 | } else { 224 | /* Otherwise `x` may be uninitialized */ 225 | return NULL; 226 | } 227 | 228 | s = c->lookup ? c->lookup(c->user, id) : NULL; 229 | if (!s) 230 | return NULL; 231 | 232 | if (id < c->segnum) { 233 | s->id = id; 234 | s->capn = c; 235 | s->next = c->seglist; 236 | c->seglist = s; 237 | s->hdr.parent = &y->hdr; 238 | *x = &s->hdr; 239 | c->segtree = capn_tree_insert(c->segtree, &s->hdr); 240 | } else { 241 | c->segnum = id; 242 | capn_append_segment(c, s); 243 | } 244 | 245 | return s; 246 | } 247 | 248 | static uint64_t lookup_double(struct capn_segment **s, char **d, uint64_t val) { 249 | uint64_t far, tag; 250 | size_t off = (U32(val) >> 3) * 8; 251 | char *p; 252 | 253 | if ((*s = lookup_segment((*s)->capn, *s, U32(val >> 32))) == NULL) { 254 | return 0; 255 | } 256 | 257 | p = (*s)->data + off; 258 | if (off + 16 > (*s)->len) { 259 | return 0; 260 | } 261 | 262 | far = capn_flip64(*(uint64_t*) p); 263 | tag = capn_flip64(*(uint64_t*) (p+8)); 264 | 265 | /* the far tag should not be another double, and the tag 266 | * should be struct/list and have no offset */ 267 | if ((far&7) != FAR_PTR || U32(tag) > LIST_PTR) { 268 | return 0; 269 | } 270 | 271 | if ((*s = lookup_segment((*s)->capn, *s, U32(far >> 32))) == NULL) { 272 | return 0; 273 | } 274 | 275 | /* -8 because far pointers reference from the start of 276 | * the segment, but offsets reference the end of the 277 | * pointer data. Here *d points to where an equivalent 278 | * ptr would be. 279 | */ 280 | *d = (*s)->data - 8; 281 | return U64(U32(far) >> 3 << 2) | tag; 282 | } 283 | 284 | static uint64_t lookup_far(struct capn_segment **s, char **d, uint64_t val) { 285 | size_t off = (U32(val) >> 3) * 8; 286 | 287 | if ((*s = lookup_segment((*s)->capn, *s, U32(val >> 32))) == NULL) { 288 | return 0; 289 | } 290 | 291 | if (off + 8 > (*s)->len) { 292 | return 0; 293 | } 294 | 295 | *d = (*s)->data + off; 296 | return capn_flip64(*(uint64_t*)*d); 297 | } 298 | 299 | static char *struct_ptr(struct capn_segment *s, char *d, int minsz) { 300 | uint64_t val = capn_flip64(*(uint64_t*)d); 301 | uint16_t datasz; 302 | 303 | switch (val&7) { 304 | case FAR_PTR: 305 | val = lookup_far(&s, &d, val); 306 | break; 307 | case DOUBLE_PTR: 308 | val = lookup_double(&s, &d, val); 309 | break; 310 | } 311 | 312 | datasz = U16(val >> 32); 313 | d += (I32(U32(val)) << 1) + 8; 314 | 315 | if (val != 0 && (val&3) != STRUCT_PTR && datasz >= minsz && s->data <= d && d < s->data + s->len) { 316 | return d; 317 | } 318 | 319 | return NULL; 320 | } 321 | 322 | static capn_ptr read_ptr(struct capn_segment *s, char *d) { 323 | capn_ptr ret = {CAPN_NULL}; 324 | uint64_t val; 325 | char *e = 0; 326 | 327 | val = capn_flip64(*(uint64_t*) d); 328 | 329 | switch (val&7) { 330 | case FAR_PTR: 331 | val = lookup_far(&s, &d, val); 332 | ret.has_ptr_tag = (U32(val) >> 2) == 0; 333 | break; 334 | case DOUBLE_PTR: 335 | val = lookup_double(&s, &d, val); 336 | break; 337 | } 338 | 339 | d += (I32(U32(val)) >> 2) * 8 + 8; 340 | 341 | if (d < s->data) { 342 | goto err; 343 | } 344 | 345 | switch (val & 3) { 346 | case STRUCT_PTR: 347 | ret.type = val ? CAPN_STRUCT : CAPN_NULL; 348 | goto struct_common; 349 | 350 | struct_common: 351 | ret.datasz = U32(U16(val >> 32)) * 8; 352 | ret.ptrs = U32(U16(val >> 48)); 353 | e = d + ret.datasz + 8 * ret.ptrs; 354 | break; 355 | 356 | case LIST_PTR: 357 | ret.type = CAPN_LIST; 358 | ret.len = val >> 35; 359 | 360 | switch ((val >> 32) & 7) { 361 | case VOID_LIST: 362 | e = d; 363 | break; 364 | case BIT_1_LIST: 365 | ret.type = CAPN_BIT_LIST; 366 | ret.datasz = (ret.len+7)/8; 367 | e = d + ret.datasz; 368 | break; 369 | case BYTE_1_LIST: 370 | ret.datasz = 1; 371 | e = d + ret.len; 372 | break; 373 | case BYTE_2_LIST: 374 | ret.datasz = 2; 375 | e = d + ret.len * 2; 376 | break; 377 | case BYTE_4_LIST: 378 | ret.datasz = 4; 379 | e = d + ret.len * 4; 380 | break; 381 | case BYTE_8_LIST: 382 | ret.datasz = 8; 383 | e = d + ret.len * 8; 384 | break; 385 | case PTR_LIST: 386 | ret.type = CAPN_PTR_LIST; 387 | e = d + ret.len * 8; 388 | break; 389 | case COMPOSITE_LIST: 390 | if ((size_t)((d+8) - s->data) > s->len) { 391 | goto err; 392 | } 393 | 394 | val = capn_flip64(*(uint64_t*) d); 395 | 396 | d += 8; 397 | e = d + ret.len * 8; 398 | 399 | ret.datasz = U32(U16(val >> 32)) * 8; 400 | ret.ptrs = U32(U16(val >> 48)); 401 | ret.len = U32(val) >> 2; 402 | ret.is_composite_list = 1; 403 | 404 | if ((ret.datasz + 8*ret.ptrs) * ret.len != e - d) { 405 | goto err; 406 | } 407 | break; 408 | } 409 | break; 410 | 411 | default: 412 | goto err; 413 | } 414 | 415 | if ((size_t)(e - s->data) > s->len) 416 | goto err; 417 | 418 | ret.data = d; 419 | ret.seg = s; 420 | return ret; 421 | err: 422 | memset(&ret, 0, sizeof(ret)); 423 | return ret; 424 | } 425 | 426 | void capn_resolve(capn_ptr *p) { 427 | if (p->type == CAPN_FAR_POINTER) { 428 | *p = read_ptr(p->seg, p->data); 429 | } 430 | } 431 | 432 | /* TODO: should this handle CAPN_BIT_LIST? */ 433 | capn_ptr capn_getp(capn_ptr p, int off, int resolve) { 434 | capn_ptr ret = {CAPN_FAR_POINTER}; 435 | ret.seg = p.seg; 436 | 437 | capn_resolve(&p); 438 | 439 | switch (p.type) { 440 | case CAPN_LIST: 441 | /* Return an inner pointer */ 442 | if (off < p.len) { 443 | capn_ptr ret = {CAPN_STRUCT}; 444 | ret.is_list_member = 1; 445 | ret.data = p.data + off * (p.datasz + 8*p.ptrs); 446 | ret.seg = p.seg; 447 | ret.datasz = p.datasz; 448 | ret.ptrs = p.ptrs; 449 | return ret; 450 | } else { 451 | goto err; 452 | } 453 | 454 | case CAPN_STRUCT: 455 | if (off >= p.ptrs) { 456 | goto err; 457 | } 458 | ret.data = p.data + p.datasz + 8*off; 459 | break; 460 | 461 | case CAPN_PTR_LIST: 462 | if (off >= p.len) { 463 | goto err; 464 | } 465 | ret.data = p.data + 8*off; 466 | break; 467 | 468 | default: 469 | goto err; 470 | } 471 | 472 | if (resolve) { 473 | ret = read_ptr(ret.seg, ret.data); 474 | } 475 | 476 | return ret; 477 | 478 | err: 479 | memset(&p, 0, sizeof(p)); 480 | return p; 481 | } 482 | 483 | static void write_ptr_tag(char *d, capn_ptr p, int off) { 484 | uint64_t val = U64(U32(I32(off/8) << 2)); 485 | 486 | switch (p.type) { 487 | case CAPN_STRUCT: 488 | val |= STRUCT_PTR | (U64(p.datasz/8) << 32) | (U64(p.ptrs) << 48); 489 | break; 490 | 491 | case CAPN_LIST: 492 | if (p.is_composite_list) { 493 | val |= LIST_PTR | (U64(COMPOSITE_LIST) << 32) | (U64(p.len * (p.datasz/8 + p.ptrs)) << 35); 494 | } else { 495 | val |= LIST_PTR | (U64(p.len) << 35); 496 | 497 | switch (p.datasz) { 498 | case 8: 499 | val |= (U64(BYTE_8_LIST) << 32); 500 | break; 501 | case 4: 502 | val |= (U64(BYTE_4_LIST) << 32); 503 | break; 504 | case 2: 505 | val |= (U64(BYTE_2_LIST) << 32); 506 | break; 507 | case 1: 508 | val |= (U64(BYTE_1_LIST) << 32); 509 | break; 510 | case 0: 511 | val |= (U64(VOID_LIST) << 32); 512 | break; 513 | } 514 | } 515 | break; 516 | 517 | case CAPN_BIT_LIST: 518 | val |= LIST_PTR | (U64(BIT_1_LIST) << 32) | (U64(p.len) << 35); 519 | break; 520 | 521 | case CAPN_PTR_LIST: 522 | val |= LIST_PTR | (U64(PTR_LIST) << 32) | (U64(p.len) << 35); 523 | break; 524 | 525 | default: 526 | val = 0; 527 | break; 528 | } 529 | 530 | *(uint64_t*) d = capn_flip64(val); 531 | } 532 | 533 | static void write_far_ptr(char *d, struct capn_segment *s, char *tgt) { 534 | *(uint64_t*) d = capn_flip64(FAR_PTR | U64(tgt - s->data) | (U64(s->id) << 32)); 535 | } 536 | 537 | static void write_double_far(char *d, struct capn_segment *s, char *tgt) { 538 | *(uint64_t*) d = capn_flip64(DOUBLE_PTR | U64(tgt - s->data) | (U64(s->id) << 32)); 539 | } 540 | 541 | #define NEED_TO_COPY 1 542 | 543 | static int write_ptr(struct capn_segment *s, char *d, capn_ptr p) { 544 | /* note p.seg can be NULL if its a ptr to static data */ 545 | char *pdata = p.data - 8*p.is_composite_list; 546 | 547 | if (p.type == CAPN_NULL || (p.type == CAPN_STRUCT && p.datasz == 0 && p.ptrs == 0)) { 548 | write_ptr_tag(d, p, 0); 549 | return 0; 550 | 551 | } else if (!p.seg || p.seg->capn != s->capn || p.is_list_member) { 552 | return NEED_TO_COPY; 553 | 554 | } else if (p.seg == s) { 555 | write_ptr_tag(d, p, pdata - d - 8); 556 | return 0; 557 | 558 | } else if (p.has_ptr_tag) { 559 | /* By lucky chance, the data has a tag in front 560 | * of it. This happens when new_object had to move 561 | * the data to a new segment. */ 562 | write_far_ptr(d, p.seg, pdata-8); 563 | return 0; 564 | 565 | } else if (p.seg->len + 8 <= p.seg->cap) { 566 | /* The target segment has enough room for tag */ 567 | char *t = p.seg->data + p.seg->len; 568 | write_ptr_tag(t, p, pdata - t - 8); 569 | write_far_ptr(d, p.seg, t); 570 | p.seg->len += 8; 571 | return 0; 572 | 573 | } else { 574 | /* have to allocate room for a double far 575 | * pointer */ 576 | char *t; 577 | 578 | if (s->len + 16 <= s->cap) { 579 | /* Try and allocate in the src segment 580 | * first. This should improve lookup on 581 | * read. */ 582 | t = s->data + s->len; 583 | s->len += 16; 584 | } else { 585 | t = new_data(s->capn, 16, &s); 586 | if (!t) return -1; 587 | } 588 | 589 | write_far_ptr(t, p.seg, pdata); 590 | write_ptr_tag(t+8, p, 0); 591 | write_double_far(d, s, t); 592 | return 0; 593 | } 594 | } 595 | 596 | struct copy { 597 | struct capn_tree hdr; 598 | struct capn_ptr to, from; 599 | char *fbegin, *fend; 600 | }; 601 | 602 | static capn_ptr new_clone(struct capn_segment *s, capn_ptr p) { 603 | switch (p.type) { 604 | case CAPN_STRUCT: 605 | return capn_new_struct(s, p.datasz, p.ptrs); 606 | case CAPN_PTR_LIST: 607 | return capn_new_ptr_list(s, p.len); 608 | case CAPN_BIT_LIST: 609 | return capn_new_list1(s, p.len).p; 610 | case CAPN_LIST: 611 | return capn_new_list(s, p.len, p.datasz, p.ptrs); 612 | default: 613 | return p; 614 | } 615 | } 616 | 617 | static int is_ptr_equal(const struct capn_ptr *a, const struct capn_ptr *b) { 618 | return a->data == b->data 619 | && a->type == b->type 620 | && a->len == b->len 621 | && a->datasz == b->datasz 622 | && a->ptrs == b->ptrs; 623 | } 624 | 625 | static int data_size(struct capn_ptr p) { 626 | switch (p.type) { 627 | case CAPN_BIT_LIST: 628 | return p.datasz; 629 | case CAPN_PTR_LIST: 630 | return p.len*8; 631 | case CAPN_STRUCT: 632 | return p.datasz + 8*p.ptrs; 633 | case CAPN_LIST: 634 | return p.len * (p.datasz + 8*p.ptrs) + 8*p.is_composite_list; 635 | default: 636 | return 0; 637 | } 638 | } 639 | 640 | static int copy_ptr(struct capn_segment *seg, char *data, struct capn_ptr *t, struct capn_ptr *f, int *dep) { 641 | struct capn *c = seg->capn; 642 | struct copy *cp = NULL; 643 | struct capn_tree **xcp; 644 | char *fbegin = f->data - 8*f->is_composite_list; 645 | char *fend = fbegin + data_size(*f); 646 | int zero_sized = (fend == fbegin); 647 | 648 | /* We always copy list members as it would otherwise be an 649 | * overlapped pointer (the data is owned by the enclosing list). 650 | * We do not bother with the overlapped lookup for zero sized 651 | * structures/lists as they never overlap. Nor do we add them to 652 | * the copy list as there is no data to be shared by multiple 653 | * pointers. 654 | */ 655 | 656 | xcp = &c->copy; 657 | while (*xcp && !zero_sized) { 658 | cp = (struct copy*) *xcp; 659 | if (fend <= cp->fbegin) { 660 | xcp = &cp->hdr.link[0]; 661 | } else if (cp->fend <= fbegin) { 662 | xcp = &cp->hdr.link[1]; 663 | } else if (is_ptr_equal(f, &cp->from)) { 664 | /* we already have a copy so just point to that */ 665 | return write_ptr(seg, data, cp->to); 666 | } else { 667 | /* pointer to overlapped data */ 668 | return -1; 669 | } 670 | } 671 | 672 | /* no copy found - have to create a new copy */ 673 | *t = new_clone(seg, *f); 674 | 675 | if (write_ptr(seg, data, *t)) 676 | return -1; 677 | 678 | /* add the copy to the copy tree so we can look for overlapping 679 | * source pointers and handle recursive structures */ 680 | if (!zero_sized) { 681 | struct copy *n; 682 | struct capn_segment *cs = c->copylist; 683 | 684 | /* need to allocate a struct copy */ 685 | if (!cs || cs->len + (int)sizeof(*n) > cs->cap) { 686 | cs = c->create_local ? c->create_local(c->user, sizeof(*n)) : NULL; 687 | if (!cs) { 688 | /* can't allocate a copy structure */ 689 | return -1; 690 | } 691 | cs->next = c->copylist; 692 | c->copylist = cs; 693 | } 694 | 695 | n = (struct copy*) (cs->data + cs->len); 696 | cs->len += sizeof(*n); 697 | 698 | n->from = *f; 699 | n->to = *t; 700 | n->fbegin = fbegin; 701 | n->fend = fend; 702 | 703 | *xcp = &n->hdr; 704 | n->hdr.parent = &cp->hdr; 705 | 706 | c->copy = capn_tree_insert(c->copy, &n->hdr); 707 | } 708 | 709 | /* minimize the number of types the main copy routine has to 710 | * deal with to just CAPN_LIST and CAPN_PTR_LIST. ptr list only 711 | * needs t->type, t->len, t->data, t->seg, f->data, f->seg to 712 | * be valid */ 713 | switch (t->type) { 714 | case CAPN_STRUCT: 715 | if (t->datasz) { 716 | memcpy(t->data, f->data, t->datasz); 717 | t->data += t->datasz; 718 | f->data += t->datasz; 719 | } 720 | if (t->ptrs) { 721 | t->type = CAPN_PTR_LIST; 722 | t->len = t->ptrs; 723 | (*dep)++; 724 | } 725 | return 0; 726 | 727 | case CAPN_BIT_LIST: 728 | memcpy(t->data, f->data, t->datasz); 729 | return 0; 730 | 731 | case CAPN_LIST: 732 | if (!t->len) { 733 | /* empty list - nothing to copy */ 734 | } else if (t->ptrs && t->datasz) { 735 | (*dep)++; 736 | } else if (t->datasz) { 737 | memcpy(t->data, f->data, t->len * t->datasz); 738 | } else if (t->ptrs) { 739 | t->type = CAPN_PTR_LIST; 740 | t->len *= t->ptrs; 741 | (*dep)++; 742 | } 743 | return 0; 744 | 745 | case CAPN_PTR_LIST: 746 | if (t->len) { 747 | (*dep)++; 748 | } 749 | return 0; 750 | 751 | default: 752 | return -1; 753 | } 754 | } 755 | 756 | static void copy_list_member(capn_ptr* t, capn_ptr *f, int *dep) { 757 | /* copy struct data */ 758 | int sz = min(t->datasz, f->datasz); 759 | memcpy(t->data, f->data, sz); 760 | memset(t->data + sz, 0, t->datasz - sz); 761 | t->data += t->datasz; 762 | f->data += f->datasz; 763 | 764 | /* reset excess pointers */ 765 | sz = min(t->ptrs, f->ptrs); 766 | memset(t->data + sz, 0, 8*(t->ptrs - sz)); 767 | 768 | /* create a pointer list for the main loop to copy */ 769 | if (t->ptrs) { 770 | t->type = CAPN_PTR_LIST; 771 | t->len = t->ptrs; 772 | (*dep)++; 773 | } 774 | } 775 | 776 | #define MAX_COPY_DEPTH 32 777 | 778 | /* TODO: handle CAPN_BIT_LIST and setting from an inner bit list member */ 779 | int capn_setp(capn_ptr p, int off, capn_ptr tgt) { 780 | struct capn_ptr to[MAX_COPY_DEPTH], from[MAX_COPY_DEPTH]; 781 | char *data; 782 | int err, dep = 0; 783 | 784 | capn_resolve(&p); 785 | 786 | if (tgt.type == CAPN_FAR_POINTER && tgt.seg->capn == p.seg->capn) { 787 | uint64_t val = capn_flip64(*(uint64_t*) tgt.data); 788 | if ((val & 3) == FAR_PTR) { 789 | *(uint64_t*) p.data = *(uint64_t*) tgt.data; 790 | return 0; 791 | } 792 | } 793 | 794 | capn_resolve(&tgt); 795 | 796 | switch (p.type) { 797 | case CAPN_LIST: 798 | if (off >= p.len || tgt.type != CAPN_STRUCT) 799 | return -1; 800 | 801 | to[0] = p; 802 | to[0].data += off * (p.datasz + 8*p.ptrs); 803 | from[0] = tgt; 804 | copy_list_member(to, from, &dep); 805 | break; 806 | 807 | case CAPN_PTR_LIST: 808 | if (off >= p.len) 809 | return -1; 810 | data = p.data + 8*off; 811 | goto copy_ptr; 812 | 813 | case CAPN_STRUCT: 814 | if (off >= p.ptrs) 815 | return -1; 816 | data = p.data + p.datasz + 8*off; 817 | goto copy_ptr; 818 | 819 | copy_ptr: 820 | err = write_ptr(p.seg, data, tgt); 821 | if (err != NEED_TO_COPY) 822 | return err; 823 | 824 | /* Depth first copy the source whilst using a pointer stack to 825 | * maintain the ptr to set and size left to copy at each level. 826 | * We also maintain a rbtree (capn->copy) of the copies indexed 827 | * by the source data. This way we can detect overlapped 828 | * pointers in the source (and bail) and recursive structures 829 | * (and point to the previous copy). 830 | */ 831 | 832 | from[0] = tgt; 833 | if (copy_ptr(p.seg, data, to, from, &dep)) 834 | return -1; 835 | break; 836 | 837 | default: 838 | return -1; 839 | } 840 | 841 | while (dep) { 842 | struct capn_ptr *tc = &to[dep-1], *tn = &to[dep]; 843 | struct capn_ptr *fc = &from[dep-1], *fn = &from[dep]; 844 | 845 | if (dep+1 == MAX_COPY_DEPTH) { 846 | return -1; 847 | } 848 | 849 | if (!tc->len) { 850 | dep--; 851 | continue; 852 | } 853 | 854 | if (tc->type == CAPN_LIST) { 855 | *fn = capn_getp(*fc, 0, 1); 856 | *tn = capn_getp(*tc, 0, 1); 857 | 858 | copy_list_member(tn, fn, &dep); 859 | 860 | fc->data += fc->datasz + 8*fc->ptrs; 861 | tc->data += tc->datasz + 8*tc->ptrs; 862 | tc->len--; 863 | 864 | } else { /* CAPN_PTR_LIST */ 865 | *fn = read_ptr(fc->seg, fc->data); 866 | 867 | if (fn->type && copy_ptr(tc->seg, tc->data, tn, fn, &dep)) 868 | return -1; 869 | 870 | fc->data += 8; 871 | tc->data += 8; 872 | tc->len--; 873 | } 874 | } 875 | 876 | return 0; 877 | } 878 | 879 | /* TODO: handle CAPN_LIST, CAPN_PTR_LIST for bit lists */ 880 | 881 | int capn_get1(capn_list1 l, int off) { 882 | return l.p.type == CAPN_BIT_LIST 883 | && off < l.p.len 884 | && (l.p.data[off/8] & (1 << (off%8))) != 0; 885 | } 886 | 887 | int capn_set1(capn_list1 l, int off, int val) { 888 | if (l.p.type != CAPN_BIT_LIST || off >= l.p.len) 889 | return -1; 890 | if (val) { 891 | l.p.data[off/8] |= 1 << (off%8); 892 | } else { 893 | l.p.data[off/8] &= ~(1 << (off%8)); 894 | } 895 | return 0; 896 | } 897 | 898 | int capn_getv1(capn_list1 l, int off, uint8_t *data, int sz) { 899 | /* Note we only support aligned reads */ 900 | int bsz; 901 | capn_ptr p; 902 | capn_resolve(&l.p); 903 | p = l.p; 904 | if (p.type != CAPN_BIT_LIST || (off & 7) != 0) 905 | return -1; 906 | 907 | bsz = (sz + 7) / 8; 908 | off /= 8; 909 | 910 | if (off + sz > p.datasz) { 911 | memcpy(data, p.data + off, p.datasz - off); 912 | return p.len - off*8; 913 | } else { 914 | memcpy(data, p.data + off, bsz); 915 | return sz; 916 | } 917 | } 918 | 919 | int capn_setv1(capn_list1 l, int off, const uint8_t *data, int sz) { 920 | /* Note we only support aligned writes */ 921 | int bsz; 922 | capn_ptr p = l.p; 923 | if (p.type != CAPN_BIT_LIST || (off & 7) != 0) 924 | return -1; 925 | 926 | bsz = (sz + 7) / 8; 927 | off /= 8; 928 | 929 | if (off + sz > p.datasz) { 930 | memcpy(p.data + off, data, p.datasz - off); 931 | return p.len - off*8; 932 | } else { 933 | memcpy(p.data + off, data, bsz); 934 | return sz; 935 | } 936 | } 937 | 938 | /* pull out whether we add a tag or not as a define so the unit test can 939 | * test double far pointers by not creating tags */ 940 | #ifndef ADD_TAG 941 | #define ADD_TAG 1 942 | #endif 943 | 944 | static void new_object(capn_ptr *p, int bytes) { 945 | struct capn_segment *s = p->seg; 946 | 947 | if (!s) { 948 | memset(p, 0, sizeof(*p)); 949 | return; 950 | } 951 | 952 | /* pointer needs to be initialised to get a valid offset on write */ 953 | if (!bytes) { 954 | p->data = s->data + s->len; 955 | return; 956 | } 957 | 958 | /* all allocations are 8 byte aligned */ 959 | bytes = (bytes + 7) & ~7; 960 | 961 | if (s->len + bytes <= s->cap) { 962 | p->data = s->data + s->len; 963 | s->len += bytes; 964 | return; 965 | } 966 | 967 | /* add a tag whenever we switch segments so that write_ptr can 968 | * use it */ 969 | p->data = new_data(s->capn, bytes + ADD_TAG*8, &p->seg); 970 | if (!p->data) { 971 | memset(p, 0, sizeof(*p)); 972 | return; 973 | } 974 | 975 | if (ADD_TAG) { 976 | write_ptr_tag(p->data, *p, 0); 977 | p->data += 8; 978 | p->has_ptr_tag = 1; 979 | } 980 | } 981 | 982 | capn_ptr capn_root(struct capn *c) { 983 | capn_ptr r = {CAPN_PTR_LIST}; 984 | r.seg = lookup_segment(c, NULL, 0); 985 | r.data = r.seg ? r.seg->data : new_data(c, 8, &r.seg); 986 | r.len = 1; 987 | 988 | if (!r.seg || r.seg->cap < 8) { 989 | memset(&r, 0, sizeof(r)); 990 | } else if (r.seg->len < 8) { 991 | r.seg->len = 8; 992 | } 993 | 994 | return r; 995 | } 996 | 997 | capn_ptr capn_new_struct(struct capn_segment *seg, int datasz, int ptrs) { 998 | capn_ptr p = {CAPN_STRUCT}; 999 | p.seg = seg; 1000 | p.datasz = (datasz + 7) & ~7; 1001 | p.ptrs = ptrs; 1002 | new_object(&p, p.datasz + 8*p.ptrs); 1003 | return p; 1004 | } 1005 | 1006 | capn_ptr capn_new_list(struct capn_segment *seg, int sz, int datasz, int ptrs) { 1007 | capn_ptr p = {CAPN_LIST}; 1008 | p.seg = seg; 1009 | p.len = sz; 1010 | 1011 | if (ptrs || datasz > 8) { 1012 | p.is_composite_list = 1; 1013 | p.datasz = (datasz + 7) & ~7; 1014 | p.ptrs = ptrs; 1015 | new_object(&p, p.len * (p.datasz + 8*p.ptrs) + 8); 1016 | if (p.data) { 1017 | uint64_t hdr = STRUCT_PTR | (U64(p.len) << 2) | (U64(p.datasz/8) << 32) | (U64(ptrs) << 48); 1018 | *(uint64_t*) p.data = capn_flip64(hdr); 1019 | p.data += 8; 1020 | } 1021 | } else if (datasz > 4) { 1022 | p.datasz = 8; 1023 | new_object(&p, p.len * 8); 1024 | } else if (datasz > 2) { 1025 | p.datasz = 4; 1026 | new_object(&p, p.len * 4); 1027 | } else { 1028 | p.datasz = datasz; 1029 | new_object(&p, p.len * datasz); 1030 | } 1031 | 1032 | return p; 1033 | } 1034 | 1035 | capn_list1 capn_new_list1(struct capn_segment *seg, int sz) { 1036 | capn_list1 l = {{CAPN_BIT_LIST}}; 1037 | l.p.seg = seg; 1038 | l.p.datasz = (sz+7)/8; 1039 | l.p.len = sz; 1040 | new_object(&l.p, l.p.datasz); 1041 | return l; 1042 | } 1043 | 1044 | capn_ptr capn_new_ptr_list(struct capn_segment *seg, int sz) { 1045 | capn_ptr p = {CAPN_PTR_LIST}; 1046 | p.seg = seg; 1047 | p.len = sz; 1048 | p.ptrs = 0; 1049 | p.datasz = 0; 1050 | new_object(&p, sz*8); 1051 | return p; 1052 | } 1053 | 1054 | capn_ptr capn_new_string(struct capn_segment *seg, const char *str, ssize_t sz) { 1055 | capn_ptr p = {CAPN_LIST}; 1056 | p.seg = seg; 1057 | p.len = ((sz >= 0) ? (size_t)sz : strlen(str)) + 1; 1058 | p.datasz = 1; 1059 | new_object(&p, p.len); 1060 | if (p.data) { 1061 | memcpy(p.data, str, p.len - 1); 1062 | p.data[p.len - 1] = '\0'; 1063 | } 1064 | return p; 1065 | } 1066 | 1067 | capn_text capn_get_text(capn_ptr p, int off, capn_text def) { 1068 | capn_ptr m = capn_getp(p, off, 1); 1069 | capn_text ret = def; 1070 | if (m.type == CAPN_LIST && m.datasz == 1 && m.len && m.data[m.len - 1] == 0) { 1071 | ret.seg = m.seg; 1072 | ret.str = m.data; 1073 | ret.len = m.len - 1; 1074 | } 1075 | return ret; 1076 | } 1077 | 1078 | int capn_set_text(capn_ptr p, int off, capn_text tgt) { 1079 | capn_ptr m = {CAPN_NULL}; 1080 | if (tgt.seg) { 1081 | m.type = CAPN_LIST; 1082 | m.seg = tgt.seg; 1083 | m.data = (char*)tgt.str; 1084 | m.len = tgt.len + 1; 1085 | m.datasz = 1; 1086 | } else if (tgt.str) { 1087 | m = capn_new_string(p.seg, tgt.str, tgt.len); 1088 | } 1089 | return capn_setp(p, off, m); 1090 | } 1091 | 1092 | capn_data capn_get_data(capn_ptr p, int off) { 1093 | capn_data ret; 1094 | ret.p = capn_getp(p, off, 1); 1095 | if (ret.p.type != CAPN_LIST || ret.p.datasz != 1) { 1096 | memset(&ret, 0, sizeof(ret)); 1097 | } 1098 | return ret; 1099 | } 1100 | 1101 | #define SZ 8 1102 | #include "capn-list.inc" 1103 | #undef SZ 1104 | 1105 | #define SZ 16 1106 | #include "capn-list.inc" 1107 | #undef SZ 1108 | 1109 | #define SZ 32 1110 | #include "capn-list.inc" 1111 | #undef SZ 1112 | 1113 | #define SZ 64 1114 | #include "capn-list.inc" 1115 | #undef SZ 1116 | --------------------------------------------------------------------------------