snowflake-connector-python 3.16.0__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/connector/__init__.py +96 -0
- snowflake/connector/_query_context_cache.py +276 -0
- snowflake/connector/_sql_util.py +48 -0
- snowflake/connector/_utils.py +70 -0
- snowflake/connector/arrow_context.py +203 -0
- snowflake/connector/auth/__init__.py +53 -0
- snowflake/connector/auth/_auth.py +586 -0
- snowflake/connector/auth/_http_server.py +220 -0
- snowflake/connector/auth/_oauth_base.py +400 -0
- snowflake/connector/auth/by_plugin.py +219 -0
- snowflake/connector/auth/default.py +36 -0
- snowflake/connector/auth/idtoken.py +72 -0
- snowflake/connector/auth/keypair.py +222 -0
- snowflake/connector/auth/no_auth.py +39 -0
- snowflake/connector/auth/oauth.py +49 -0
- snowflake/connector/auth/oauth_code.py +479 -0
- snowflake/connector/auth/oauth_credentials.py +66 -0
- snowflake/connector/auth/okta.py +335 -0
- snowflake/connector/auth/pat.py +39 -0
- snowflake/connector/auth/usrpwdmfa.py +69 -0
- snowflake/connector/auth/webbrowser.py +502 -0
- snowflake/connector/auth/workload_identity.py +94 -0
- snowflake/connector/azure_storage_client.py +276 -0
- snowflake/connector/backoff_policies.py +141 -0
- snowflake/connector/bind_upload_agent.py +89 -0
- snowflake/connector/cache.py +696 -0
- snowflake/connector/compat.py +127 -0
- snowflake/connector/config_manager.py +496 -0
- snowflake/connector/connection.py +2273 -0
- snowflake/connector/connection_diagnostic.py +776 -0
- snowflake/connector/constants.py +442 -0
- snowflake/connector/converter.py +785 -0
- snowflake/connector/converter_issue23517.py +87 -0
- snowflake/connector/converter_null.py +14 -0
- snowflake/connector/converter_snowsql.py +205 -0
- snowflake/connector/cursor.py +1951 -0
- snowflake/connector/dbapi.py +53 -0
- snowflake/connector/description.py +19 -0
- snowflake/connector/direct_file_operation_utils.py +88 -0
- snowflake/connector/encryption_util.py +220 -0
- snowflake/connector/errorcode.py +91 -0
- snowflake/connector/errors.py +615 -0
- snowflake/connector/externals_utils/__init__.py +0 -0
- snowflake/connector/externals_utils/externals_setup.py +27 -0
- snowflake/connector/feature.py +4 -0
- snowflake/connector/file_compression_type.py +118 -0
- snowflake/connector/file_lock.py +72 -0
- snowflake/connector/file_transfer_agent.py +1215 -0
- snowflake/connector/file_util.py +153 -0
- snowflake/connector/gcs_storage_client.py +474 -0
- snowflake/connector/gzip_decoder.py +85 -0
- snowflake/connector/local_storage_client.py +90 -0
- snowflake/connector/log_configuration.py +60 -0
- snowflake/connector/logging_utils/__init__.py +0 -0
- snowflake/connector/logging_utils/filters.py +72 -0
- snowflake/connector/nanoarrow_arrow_iterator.cp313-win_amd64.pyd +0 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +557 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1005 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +127 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +71 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +56 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +256 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
- snowflake/connector/network.py +1297 -0
- snowflake/connector/ocsp_asn1crypto.py +447 -0
- snowflake/connector/ocsp_snowflake.py +1883 -0
- snowflake/connector/options.py +131 -0
- snowflake/connector/pandas_tools.py +732 -0
- snowflake/connector/proxy.py +43 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +786 -0
- snowflake/connector/result_set.py +319 -0
- snowflake/connector/s3_storage_client.py +605 -0
- snowflake/connector/secret_detector.py +181 -0
- snowflake/connector/sf_dirs.py +64 -0
- snowflake/connector/sfbinaryformat.py +35 -0
- snowflake/connector/sfdatetime.py +345 -0
- snowflake/connector/snow_logging.py +144 -0
- snowflake/connector/sqlstate.py +9 -0
- snowflake/connector/ssd_internal_keys.py +30 -0
- snowflake/connector/ssl_wrap_socket.py +134 -0
- snowflake/connector/storage_client.py +478 -0
- snowflake/connector/telemetry.py +249 -0
- snowflake/connector/telemetry_oob.py +543 -0
- snowflake/connector/test_util.py +30 -0
- snowflake/connector/time_util.py +159 -0
- snowflake/connector/token_cache.py +402 -0
- snowflake/connector/tool/__init__.py +0 -0
- snowflake/connector/tool/dump_certs.py +57 -0
- snowflake/connector/tool/dump_ocsp_response.py +139 -0
- snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
- snowflake/connector/tool/probe_connection.py +69 -0
- snowflake/connector/url_util.py +49 -0
- snowflake/connector/util_text.py +301 -0
- snowflake/connector/vendored/__init__.py +3 -0
- snowflake/connector/vendored/requests/LICENSE +175 -0
- snowflake/connector/vendored/requests/__init__.py +169 -0
- snowflake/connector/vendored/requests/__version__.py +14 -0
- snowflake/connector/vendored/requests/_internal_utils.py +50 -0
- snowflake/connector/vendored/requests/adapters.py +537 -0
- snowflake/connector/vendored/requests/api.py +157 -0
- snowflake/connector/vendored/requests/auth.py +315 -0
- snowflake/connector/vendored/requests/certs.py +17 -0
- snowflake/connector/vendored/requests/compat.py +79 -0
- snowflake/connector/vendored/requests/cookies.py +561 -0
- snowflake/connector/vendored/requests/exceptions.py +140 -0
- snowflake/connector/vendored/requests/help.py +134 -0
- snowflake/connector/vendored/requests/hooks.py +33 -0
- snowflake/connector/vendored/requests/models.py +1033 -0
- snowflake/connector/vendored/requests/sessions.py +833 -0
- snowflake/connector/vendored/requests/status_codes.py +128 -0
- snowflake/connector/vendored/requests/structures.py +99 -0
- snowflake/connector/vendored/requests/utils.py +1093 -0
- snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
- snowflake/connector/vendored/urllib3/__init__.py +85 -0
- snowflake/connector/vendored/urllib3/_collections.py +355 -0
- snowflake/connector/vendored/urllib3/_version.py +2 -0
- snowflake/connector/vendored/urllib3/connection.py +572 -0
- snowflake/connector/vendored/urllib3/connectionpool.py +1137 -0
- snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +36 -0
- snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +519 -0
- snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +397 -0
- snowflake/connector/vendored/urllib3/contrib/appengine.py +314 -0
- snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +130 -0
- snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +509 -0
- snowflake/connector/vendored/urllib3/contrib/securetransport.py +920 -0
- snowflake/connector/vendored/urllib3/contrib/socks.py +216 -0
- snowflake/connector/vendored/urllib3/exceptions.py +323 -0
- snowflake/connector/vendored/urllib3/fields.py +274 -0
- snowflake/connector/vendored/urllib3/filepost.py +98 -0
- snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/packages/backports/makefile.py +51 -0
- snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +155 -0
- snowflake/connector/vendored/urllib3/packages/six.py +1076 -0
- snowflake/connector/vendored/urllib3/poolmanager.py +540 -0
- snowflake/connector/vendored/urllib3/request.py +191 -0
- snowflake/connector/vendored/urllib3/response.py +885 -0
- snowflake/connector/vendored/urllib3/util/__init__.py +49 -0
- snowflake/connector/vendored/urllib3/util/connection.py +156 -0
- snowflake/connector/vendored/urllib3/util/proxy.py +57 -0
- snowflake/connector/vendored/urllib3/util/queue.py +22 -0
- snowflake/connector/vendored/urllib3/util/request.py +146 -0
- snowflake/connector/vendored/urllib3/util/response.py +107 -0
- snowflake/connector/vendored/urllib3/util/retry.py +620 -0
- snowflake/connector/vendored/urllib3/util/ssl_.py +495 -0
- snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
- snowflake/connector/vendored/urllib3/util/ssltransport.py +221 -0
- snowflake/connector/vendored/urllib3/util/timeout.py +271 -0
- snowflake/connector/vendored/urllib3/util/url.py +435 -0
- snowflake/connector/vendored/urllib3/util/wait.py +152 -0
- snowflake/connector/version.py +3 -0
- snowflake/connector/wif_util.py +407 -0
- snowflake_connector_python-3.16.0.dist-info/METADATA +1475 -0
- snowflake_connector_python-3.16.0.dist-info/RECORD +246 -0
- snowflake_connector_python-3.16.0.dist-info/WHEEL +5 -0
- snowflake_connector_python-3.16.0.dist-info/entry_points.txt +4 -0
- snowflake_connector_python-3.16.0.dist-info/licenses/LICENSE.txt +202 -0
- snowflake_connector_python-3.16.0.dist-info/licenses/NOTICE +8 -0
- snowflake_connector_python-3.16.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,3204 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Codegenerator for C, building FlatBuffers.
|
|
3
|
+
*
|
|
4
|
+
* There are several approaches, some light, some requiring a library,
|
|
5
|
+
* some with vectored I/O etc.
|
|
6
|
+
*
|
|
7
|
+
* Here we focus on a reasonable balance of light code and efficiency.
|
|
8
|
+
*
|
|
9
|
+
* Builder code is generated to a separate file that includes the
|
|
10
|
+
* generated read-only code.
|
|
11
|
+
*
|
|
12
|
+
* Mutable buffers are not supported in this version.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include <stdlib.h>
|
|
17
|
+
#include <string.h>
|
|
18
|
+
|
|
19
|
+
#include "flatcc/flatcc_builder.h"
|
|
20
|
+
#include "flatcc/flatcc_emitter.h"
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* `check` is designed to handle incorrect use errors that can be
|
|
24
|
+
* ignored in production of a tested product.
|
|
25
|
+
*
|
|
26
|
+
* `check_error` fails if condition is false and is designed to return an
|
|
27
|
+
* error code in production.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
#if FLATCC_BUILDER_ASSERT_ON_ERROR
|
|
31
|
+
#define check(cond, reason) FLATCC_BUILDER_ASSERT(cond, reason)
|
|
32
|
+
#else
|
|
33
|
+
#define check(cond, reason) ((void)0)
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#if FLATCC_BUILDER_SKIP_CHECKS
|
|
37
|
+
#define check_error(cond, err, reason) ((void)0)
|
|
38
|
+
#else
|
|
39
|
+
#define check_error(cond, err, reason) \
|
|
40
|
+
if (!(cond)) { \
|
|
41
|
+
check(cond, reason); \
|
|
42
|
+
return err; \
|
|
43
|
+
}
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
/* `strnlen` not widely supported. */
|
|
47
|
+
static inline size_t pstrnlen(const char *s, size_t max_len) {
|
|
48
|
+
const char *end = memchr(s, 0, max_len);
|
|
49
|
+
return end ? (size_t)(end - s) : max_len;
|
|
50
|
+
}
|
|
51
|
+
#undef strnlen
|
|
52
|
+
#define strnlen pstrnlen
|
|
53
|
+
|
|
54
|
+
/* Padding can be up to 255 zeroes, and 1 zero string termination byte.
|
|
55
|
+
* When two paddings are combined at nested buffers, we need twice that.
|
|
56
|
+
* Visible to emitter so it can test for zero padding in iov. */
|
|
57
|
+
const uint8_t flatcc_builder_padding_base[512] = {0};
|
|
58
|
+
#define _pad flatcc_builder_padding_base
|
|
59
|
+
|
|
60
|
+
#define uoffset_t flatbuffers_uoffset_t
|
|
61
|
+
#define soffset_t flatbuffers_soffset_t
|
|
62
|
+
#define voffset_t flatbuffers_voffset_t
|
|
63
|
+
#define utype_t flatbuffers_utype_t
|
|
64
|
+
|
|
65
|
+
#define write_uoffset __flatbuffers_uoffset_write_to_pe
|
|
66
|
+
#define write_voffset __flatbuffers_voffset_write_to_pe
|
|
67
|
+
#define write_identifier __flatbuffers_uoffset_write_to_pe
|
|
68
|
+
#define write_utype __flatbuffers_utype_write_to_pe
|
|
69
|
+
|
|
70
|
+
#define field_size sizeof(uoffset_t)
|
|
71
|
+
#define max_offset_count FLATBUFFERS_COUNT_MAX(field_size)
|
|
72
|
+
#define union_size sizeof(flatcc_builder_union_ref_t)
|
|
73
|
+
#define max_union_count FLATBUFFERS_COUNT_MAX(union_size)
|
|
74
|
+
#define utype_size sizeof(utype_t)
|
|
75
|
+
#define max_utype_count FLATBUFFERS_COUNT_MAX(utype_size)
|
|
76
|
+
|
|
77
|
+
#define max_string_len FLATBUFFERS_COUNT_MAX(1)
|
|
78
|
+
#define identifier_size FLATBUFFERS_IDENTIFIER_SIZE
|
|
79
|
+
|
|
80
|
+
#define iovec_t flatcc_iovec_t
|
|
81
|
+
#define frame_size sizeof(__flatcc_builder_frame_t)
|
|
82
|
+
#define frame(x) (B->frame[0].x)
|
|
83
|
+
|
|
84
|
+
/* `align` must be a power of 2. */
|
|
85
|
+
static inline uoffset_t alignup_uoffset(uoffset_t x, size_t align) {
|
|
86
|
+
return (x + (uoffset_t)align - 1u) & ~((uoffset_t)align - 1u);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static inline size_t alignup_size(size_t x, size_t align) {
|
|
90
|
+
return (x + align - 1u) & ~(align - 1u);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
typedef struct vtable_descriptor vtable_descriptor_t;
|
|
94
|
+
struct vtable_descriptor {
|
|
95
|
+
/* Where the vtable is emitted. */
|
|
96
|
+
flatcc_builder_ref_t vt_ref;
|
|
97
|
+
/* Which buffer it was emitted to. */
|
|
98
|
+
uoffset_t nest_id;
|
|
99
|
+
/* Where the vtable is cached. */
|
|
100
|
+
uoffset_t vb_start;
|
|
101
|
+
/* Hash table collision chain. */
|
|
102
|
+
uoffset_t next;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
typedef struct flatcc_iov_state flatcc_iov_state_t;
|
|
106
|
+
struct flatcc_iov_state {
|
|
107
|
+
size_t len;
|
|
108
|
+
int count;
|
|
109
|
+
flatcc_iovec_t iov[FLATCC_IOV_COUNT_MAX];
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
#define iov_state_t flatcc_iov_state_t
|
|
113
|
+
|
|
114
|
+
/* This assumes `iov_state_t iov;` has been declared in scope */
|
|
115
|
+
#define push_iov_cond(base, size, cond) \
|
|
116
|
+
if ((size) > 0 && (cond)) { \
|
|
117
|
+
iov.len += size; \
|
|
118
|
+
iov.iov[iov.count].iov_base = (void *)(base); \
|
|
119
|
+
iov.iov[iov.count].iov_len = (size); \
|
|
120
|
+
++iov.count; \
|
|
121
|
+
}
|
|
122
|
+
#define push_iov(base, size) push_iov_cond(base, size, 1)
|
|
123
|
+
#define init_iov() \
|
|
124
|
+
{ \
|
|
125
|
+
iov.len = 0; \
|
|
126
|
+
iov.count = 0; \
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
int flatcc_builder_default_alloc(void *alloc_context, iovec_t *b,
|
|
130
|
+
size_t request, int zero_fill, int hint) {
|
|
131
|
+
void *p;
|
|
132
|
+
size_t n;
|
|
133
|
+
|
|
134
|
+
(void)alloc_context;
|
|
135
|
+
|
|
136
|
+
if (request == 0) {
|
|
137
|
+
if (b->iov_base) {
|
|
138
|
+
FLATCC_BUILDER_FREE(b->iov_base);
|
|
139
|
+
b->iov_base = 0;
|
|
140
|
+
b->iov_len = 0;
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
switch (hint) {
|
|
145
|
+
case flatcc_builder_alloc_ds:
|
|
146
|
+
n = 256;
|
|
147
|
+
break;
|
|
148
|
+
case flatcc_builder_alloc_ht:
|
|
149
|
+
/* Should be exact size, or space size is just wasted. */
|
|
150
|
+
n = request;
|
|
151
|
+
break;
|
|
152
|
+
case flatcc_builder_alloc_fs:
|
|
153
|
+
n = sizeof(__flatcc_builder_frame_t) * 8;
|
|
154
|
+
break;
|
|
155
|
+
case flatcc_builder_alloc_us:
|
|
156
|
+
n = 64;
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
/*
|
|
160
|
+
* We have many small structures - vs stack for tables with few
|
|
161
|
+
* elements, and few offset fields in patch log. No need to
|
|
162
|
+
* overallocate in case of busy small messages.
|
|
163
|
+
*/
|
|
164
|
+
n = 32;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
while (n < request) {
|
|
168
|
+
n *= 2;
|
|
169
|
+
}
|
|
170
|
+
if (request <= b->iov_len && b->iov_len / 2 >= n) {
|
|
171
|
+
/* Add hysteresis to shrink. */
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
if (!(p = FLATCC_BUILDER_REALLOC(b->iov_base, n))) {
|
|
175
|
+
return -1;
|
|
176
|
+
}
|
|
177
|
+
/* Realloc might also shrink. */
|
|
178
|
+
if (zero_fill && b->iov_len < n) {
|
|
179
|
+
memset((uint8_t *)p + b->iov_len, 0, n - b->iov_len);
|
|
180
|
+
}
|
|
181
|
+
b->iov_base = p;
|
|
182
|
+
b->iov_len = n;
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
#define T_ptr(base, pos) ((void *)((uint8_t *)(base) + (uoffset_t)(pos)))
|
|
187
|
+
#define ds_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_ds].iov_base, (pos)))
|
|
188
|
+
#define vs_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vs].iov_base, (pos)))
|
|
189
|
+
#define pl_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_pl].iov_base, (pos)))
|
|
190
|
+
#define us_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_us].iov_base, (pos)))
|
|
191
|
+
#define vd_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vd].iov_base, (pos)))
|
|
192
|
+
#define vb_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vb].iov_base, (pos)))
|
|
193
|
+
#define vs_offset(ptr) \
|
|
194
|
+
((uoffset_t)((size_t)(ptr) - \
|
|
195
|
+
(size_t)B->buffers[flatcc_builder_alloc_vs].iov_base))
|
|
196
|
+
#define pl_offset(ptr) \
|
|
197
|
+
((uoffset_t)((size_t)(ptr) - \
|
|
198
|
+
(size_t)B->buffers[flatcc_builder_alloc_pl].iov_base))
|
|
199
|
+
#define us_offset(ptr) \
|
|
200
|
+
((uoffset_t)((size_t)(ptr) - \
|
|
201
|
+
(size_t)B->buffers[flatcc_builder_alloc_us].iov_base))
|
|
202
|
+
|
|
203
|
+
#define table_limit (FLATBUFFERS_VOFFSET_MAX - field_size + 1)
|
|
204
|
+
#define data_limit (FLATBUFFERS_UOFFSET_MAX - field_size + 1)
|
|
205
|
+
|
|
206
|
+
#define set_identifier(id) \
|
|
207
|
+
memcpy(&B->identifier, (id) ? (void *)(id) : (void *)_pad, identifier_size)
|
|
208
|
+
|
|
209
|
+
/* Must also return true when no buffer has been started. */
|
|
210
|
+
#define is_top_buffer(B) (B->nest_id == 0)
|
|
211
|
+
|
|
212
|
+
/*
|
|
213
|
+
* Tables use a stack represention better suited for quickly adding
|
|
214
|
+
* fields to tables, but it must occasionally be refreshed following
|
|
215
|
+
* reallocation or reentry from child frame.
|
|
216
|
+
*/
|
|
217
|
+
static inline void refresh_ds(flatcc_builder_t *B, uoffset_t type_limit) {
|
|
218
|
+
iovec_t *buf = B->buffers + flatcc_builder_alloc_ds;
|
|
219
|
+
|
|
220
|
+
B->ds = ds_ptr(B->ds_first);
|
|
221
|
+
B->ds_limit = (uoffset_t)buf->iov_len - B->ds_first;
|
|
222
|
+
/*
|
|
223
|
+
* So we don't allocate outside tables representation size, nor our
|
|
224
|
+
* current buffer size.
|
|
225
|
+
*/
|
|
226
|
+
if (B->ds_limit > type_limit) {
|
|
227
|
+
B->ds_limit = type_limit;
|
|
228
|
+
}
|
|
229
|
+
/* So exit frame can refresh fast. */
|
|
230
|
+
frame(type_limit) = type_limit;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static int reserve_ds(flatcc_builder_t *B, size_t need, uoffset_t limit) {
|
|
234
|
+
iovec_t *buf = B->buffers + flatcc_builder_alloc_ds;
|
|
235
|
+
|
|
236
|
+
if (B->alloc(B->alloc_context, buf, B->ds_first + need, 1,
|
|
237
|
+
flatcc_builder_alloc_ds)) {
|
|
238
|
+
return -1;
|
|
239
|
+
}
|
|
240
|
+
refresh_ds(B, limit);
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* Make sure there is always an extra zero termination on stack
|
|
246
|
+
* even if it isn't emitted such that string updates may count
|
|
247
|
+
* on zero termination being present always.
|
|
248
|
+
*/
|
|
249
|
+
static inline void *push_ds(flatcc_builder_t *B, uoffset_t size) {
|
|
250
|
+
size_t offset;
|
|
251
|
+
|
|
252
|
+
offset = B->ds_offset;
|
|
253
|
+
if ((B->ds_offset += size) >= B->ds_limit) {
|
|
254
|
+
if (reserve_ds(B, B->ds_offset + 1, data_limit)) {
|
|
255
|
+
return 0;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return B->ds + offset;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static inline void unpush_ds(flatcc_builder_t *B, uoffset_t size) {
|
|
262
|
+
B->ds_offset -= size;
|
|
263
|
+
memset(B->ds + B->ds_offset, 0, size);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static inline void *push_ds_copy(flatcc_builder_t *B, const void *data,
|
|
267
|
+
uoffset_t size) {
|
|
268
|
+
void *p;
|
|
269
|
+
|
|
270
|
+
if (!(p = push_ds(B, size))) {
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
memcpy(p, data, size);
|
|
274
|
+
return p;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
static inline void *push_ds_field(flatcc_builder_t *B, uoffset_t size,
|
|
278
|
+
uint16_t align, voffset_t id) {
|
|
279
|
+
uoffset_t offset;
|
|
280
|
+
|
|
281
|
+
/*
|
|
282
|
+
* We calculate table field alignment relative to first entry, not
|
|
283
|
+
* header field with vtable offset.
|
|
284
|
+
*
|
|
285
|
+
* Note: >= comparison handles special case where B->ds is not
|
|
286
|
+
* allocated yet and size is 0 so the return value would be mistaken
|
|
287
|
+
* for an error.
|
|
288
|
+
*/
|
|
289
|
+
offset = alignup_uoffset(B->ds_offset, align);
|
|
290
|
+
if ((B->ds_offset = offset + size) >= B->ds_limit) {
|
|
291
|
+
if (reserve_ds(B, B->ds_offset + 1, table_limit)) {
|
|
292
|
+
return 0;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
B->vs[id] = (voffset_t)(offset + field_size);
|
|
296
|
+
if (id >= B->id_end) {
|
|
297
|
+
B->id_end = id + 1u;
|
|
298
|
+
}
|
|
299
|
+
return B->ds + offset;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
static inline void *push_ds_offset_field(flatcc_builder_t *B, voffset_t id) {
|
|
303
|
+
uoffset_t offset;
|
|
304
|
+
|
|
305
|
+
offset = alignup_uoffset(B->ds_offset, field_size);
|
|
306
|
+
if ((B->ds_offset = offset + field_size) > B->ds_limit) {
|
|
307
|
+
if (reserve_ds(B, B->ds_offset, table_limit)) {
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
B->vs[id] = (voffset_t)(offset + field_size);
|
|
312
|
+
if (id >= B->id_end) {
|
|
313
|
+
B->id_end = id + 1u;
|
|
314
|
+
}
|
|
315
|
+
*B->pl++ = (flatbuffers_voffset_t)offset;
|
|
316
|
+
return B->ds + offset;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
static inline void *reserve_buffer(flatcc_builder_t *B, int alloc_type,
|
|
320
|
+
size_t used, size_t need, int zero_init) {
|
|
321
|
+
iovec_t *buf = B->buffers + alloc_type;
|
|
322
|
+
|
|
323
|
+
if (used + need > buf->iov_len) {
|
|
324
|
+
if (B->alloc(B->alloc_context, buf, used + need, zero_init, alloc_type)) {
|
|
325
|
+
check(0, "memory allocation failed");
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return (void *)((size_t)buf->iov_base + used);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static inline int reserve_fields(flatcc_builder_t *B, int count) {
|
|
333
|
+
size_t used, need;
|
|
334
|
+
|
|
335
|
+
/* Provide faster stack operations for common table operations. */
|
|
336
|
+
used = frame(container.table.vs_end) +
|
|
337
|
+
frame(container.table.id_end) * sizeof(voffset_t);
|
|
338
|
+
need = (size_t)(count + 2) * sizeof(voffset_t);
|
|
339
|
+
if (!(B->vs = reserve_buffer(B, flatcc_builder_alloc_vs, used, need, 1))) {
|
|
340
|
+
return -1;
|
|
341
|
+
}
|
|
342
|
+
/* Move past header for convenience. */
|
|
343
|
+
B->vs += 2;
|
|
344
|
+
used = frame(container.table.pl_end);
|
|
345
|
+
/* Add one to handle special case of first table being empty. */
|
|
346
|
+
need = (size_t)count * sizeof(*(B->pl)) + 1;
|
|
347
|
+
if (!(B->pl = reserve_buffer(B, flatcc_builder_alloc_pl, used, need, 0))) {
|
|
348
|
+
return -1;
|
|
349
|
+
}
|
|
350
|
+
return 0;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
static int alloc_ht(flatcc_builder_t *B) {
|
|
354
|
+
iovec_t *buf = B->buffers + flatcc_builder_alloc_ht;
|
|
355
|
+
|
|
356
|
+
size_t size, k;
|
|
357
|
+
/* Allocate null entry so we can check for return errors. */
|
|
358
|
+
FLATCC_ASSERT(B->vd_end == 0);
|
|
359
|
+
if (!reserve_buffer(B, flatcc_builder_alloc_vd, B->vd_end,
|
|
360
|
+
sizeof(vtable_descriptor_t), 0)) {
|
|
361
|
+
return -1;
|
|
362
|
+
}
|
|
363
|
+
B->vd_end = sizeof(vtable_descriptor_t);
|
|
364
|
+
size = field_size * FLATCC_BUILDER_MIN_HASH_COUNT;
|
|
365
|
+
if (B->alloc(B->alloc_context, buf, size, 1, flatcc_builder_alloc_ht)) {
|
|
366
|
+
return -1;
|
|
367
|
+
}
|
|
368
|
+
while (size * 2 <= buf->iov_len) {
|
|
369
|
+
size *= 2;
|
|
370
|
+
}
|
|
371
|
+
size /= field_size;
|
|
372
|
+
for (k = 0; (((size_t)1) << k) < size; ++k) {
|
|
373
|
+
}
|
|
374
|
+
B->ht_width = k;
|
|
375
|
+
return 0;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
static inline uoffset_t *lookup_ht(flatcc_builder_t *B, uint32_t hash) {
|
|
379
|
+
uoffset_t *T;
|
|
380
|
+
|
|
381
|
+
if (B->ht_width == 0) {
|
|
382
|
+
if (alloc_ht(B)) {
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
T = B->buffers[flatcc_builder_alloc_ht].iov_base;
|
|
387
|
+
|
|
388
|
+
return &T[FLATCC_BUILDER_BUCKET_VT_HASH(hash, B->ht_width)];
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
void flatcc_builder_flush_vtable_cache(flatcc_builder_t *B) {
|
|
392
|
+
iovec_t *buf = B->buffers + flatcc_builder_alloc_ht;
|
|
393
|
+
|
|
394
|
+
if (B->ht_width == 0) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
memset(buf->iov_base, 0, buf->iov_len);
|
|
398
|
+
/* Reserve the null entry. */
|
|
399
|
+
B->vd_end = sizeof(vtable_descriptor_t);
|
|
400
|
+
B->vb_end = 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
int flatcc_builder_custom_init(flatcc_builder_t *B,
|
|
404
|
+
flatcc_builder_emit_fun *emit,
|
|
405
|
+
void *emit_context,
|
|
406
|
+
flatcc_builder_alloc_fun *alloc,
|
|
407
|
+
void *alloc_context) {
|
|
408
|
+
/*
|
|
409
|
+
* Do not allocate anything here. Only the required buffers will be
|
|
410
|
+
* allocated. For simple struct buffers, no allocation is required
|
|
411
|
+
* at all.
|
|
412
|
+
*/
|
|
413
|
+
memset(B, 0, sizeof(*B));
|
|
414
|
+
|
|
415
|
+
if (emit == 0) {
|
|
416
|
+
B->is_default_emitter = 1;
|
|
417
|
+
emit = flatcc_emitter;
|
|
418
|
+
emit_context = &B->default_emit_context;
|
|
419
|
+
}
|
|
420
|
+
if (alloc == 0) {
|
|
421
|
+
alloc = flatcc_builder_default_alloc;
|
|
422
|
+
}
|
|
423
|
+
B->alloc_context = alloc_context;
|
|
424
|
+
B->alloc = alloc;
|
|
425
|
+
B->emit_context = emit_context;
|
|
426
|
+
B->emit = emit;
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
int flatcc_builder_init(flatcc_builder_t *B) {
|
|
431
|
+
return flatcc_builder_custom_init(B, 0, 0, 0, 0);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
int flatcc_builder_custom_reset(flatcc_builder_t *B, int set_defaults,
|
|
435
|
+
int reduce_buffers) {
|
|
436
|
+
iovec_t *buf;
|
|
437
|
+
int i;
|
|
438
|
+
|
|
439
|
+
for (i = 0; i < FLATCC_BUILDER_ALLOC_BUFFER_COUNT; ++i) {
|
|
440
|
+
buf = B->buffers + i;
|
|
441
|
+
if (buf->iov_base) {
|
|
442
|
+
/* Don't try to reduce the hash table. */
|
|
443
|
+
if (i != flatcc_builder_alloc_ht && reduce_buffers &&
|
|
444
|
+
B->alloc(B->alloc_context, buf, 1, 1, i)) {
|
|
445
|
+
return -1;
|
|
446
|
+
}
|
|
447
|
+
memset(buf->iov_base, 0, buf->iov_len);
|
|
448
|
+
} else {
|
|
449
|
+
FLATCC_ASSERT(buf->iov_len == 0);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
B->vb_end = 0;
|
|
453
|
+
if (B->vd_end > 0) {
|
|
454
|
+
/* Reset past null entry. */
|
|
455
|
+
B->vd_end = sizeof(vtable_descriptor_t);
|
|
456
|
+
}
|
|
457
|
+
B->min_align = 0;
|
|
458
|
+
B->emit_start = 0;
|
|
459
|
+
B->emit_end = 0;
|
|
460
|
+
B->level = 0;
|
|
461
|
+
B->limit_level = 0;
|
|
462
|
+
B->ds_offset = 0;
|
|
463
|
+
B->ds_limit = 0;
|
|
464
|
+
B->nest_count = 0;
|
|
465
|
+
B->nest_id = 0;
|
|
466
|
+
/* Needed for correct offset calculation. */
|
|
467
|
+
B->ds = B->buffers[flatcc_builder_alloc_ds].iov_base;
|
|
468
|
+
B->pl = B->buffers[flatcc_builder_alloc_pl].iov_base;
|
|
469
|
+
B->vs = B->buffers[flatcc_builder_alloc_vs].iov_base;
|
|
470
|
+
B->frame = 0;
|
|
471
|
+
if (set_defaults) {
|
|
472
|
+
B->vb_flush_limit = 0;
|
|
473
|
+
B->max_level = 0;
|
|
474
|
+
B->disable_vt_clustering = 0;
|
|
475
|
+
}
|
|
476
|
+
if (B->is_default_emitter) {
|
|
477
|
+
flatcc_emitter_reset(&B->default_emit_context);
|
|
478
|
+
}
|
|
479
|
+
if (B->refmap) {
|
|
480
|
+
flatcc_refmap_reset(B->refmap);
|
|
481
|
+
}
|
|
482
|
+
return 0;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
int flatcc_builder_reset(flatcc_builder_t *B) {
|
|
486
|
+
return flatcc_builder_custom_reset(B, 0, 0);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
void flatcc_builder_clear(flatcc_builder_t *B) {
|
|
490
|
+
iovec_t *buf;
|
|
491
|
+
int i;
|
|
492
|
+
|
|
493
|
+
for (i = 0; i < FLATCC_BUILDER_ALLOC_BUFFER_COUNT; ++i) {
|
|
494
|
+
buf = B->buffers + i;
|
|
495
|
+
B->alloc(B->alloc_context, buf, 0, 0, i);
|
|
496
|
+
}
|
|
497
|
+
if (B->is_default_emitter) {
|
|
498
|
+
flatcc_emitter_clear(&B->default_emit_context);
|
|
499
|
+
}
|
|
500
|
+
if (B->refmap) {
|
|
501
|
+
flatcc_refmap_clear(B->refmap);
|
|
502
|
+
}
|
|
503
|
+
memset(B, 0, sizeof(*B));
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
static inline void set_min_align(flatcc_builder_t *B, uint16_t align) {
|
|
507
|
+
if (B->min_align < align) {
|
|
508
|
+
B->min_align = align;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/*
|
|
513
|
+
* It's a max, but the minimum viable alignment is the largest observed
|
|
514
|
+
* alignment requirement, but no larger.
|
|
515
|
+
*/
|
|
516
|
+
static inline void get_min_align(uint16_t *align, uint16_t b) {
|
|
517
|
+
if (*align < b) {
|
|
518
|
+
*align = b;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
void *flatcc_builder_enter_user_frame_ptr(flatcc_builder_t *B, size_t size) {
|
|
523
|
+
size_t *frame;
|
|
524
|
+
|
|
525
|
+
size = alignup_size(size, sizeof(size_t)) + sizeof(size_t);
|
|
526
|
+
|
|
527
|
+
if (!(frame = reserve_buffer(B, flatcc_builder_alloc_us, B->user_frame_end,
|
|
528
|
+
size, 0))) {
|
|
529
|
+
return 0;
|
|
530
|
+
}
|
|
531
|
+
memset(frame, 0, size);
|
|
532
|
+
*frame++ = B->user_frame_offset;
|
|
533
|
+
B->user_frame_offset = B->user_frame_end + sizeof(size_t);
|
|
534
|
+
B->user_frame_end += size;
|
|
535
|
+
return frame;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
size_t flatcc_builder_enter_user_frame(flatcc_builder_t *B, size_t size) {
|
|
539
|
+
size_t *frame;
|
|
540
|
+
|
|
541
|
+
size = alignup_size(size, sizeof(size_t)) + sizeof(size_t);
|
|
542
|
+
|
|
543
|
+
if (!(frame = reserve_buffer(B, flatcc_builder_alloc_us, B->user_frame_end,
|
|
544
|
+
size, 0))) {
|
|
545
|
+
return 0;
|
|
546
|
+
}
|
|
547
|
+
memset(frame, 0, size);
|
|
548
|
+
*frame++ = B->user_frame_offset;
|
|
549
|
+
B->user_frame_offset = B->user_frame_end + sizeof(size_t);
|
|
550
|
+
B->user_frame_end += size;
|
|
551
|
+
return B->user_frame_offset;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
size_t flatcc_builder_exit_user_frame(flatcc_builder_t *B) {
|
|
555
|
+
size_t *hdr;
|
|
556
|
+
|
|
557
|
+
FLATCC_ASSERT(B->user_frame_offset > 0);
|
|
558
|
+
|
|
559
|
+
hdr = us_ptr(B->user_frame_offset);
|
|
560
|
+
B->user_frame_end = B->user_frame_offset - sizeof(size_t);
|
|
561
|
+
return B->user_frame_offset = hdr[-1];
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
size_t flatcc_builder_exit_user_frame_at(flatcc_builder_t *B, size_t handle) {
|
|
565
|
+
FLATCC_ASSERT(B->user_frame_offset >= handle);
|
|
566
|
+
|
|
567
|
+
B->user_frame_offset = handle;
|
|
568
|
+
return flatcc_builder_exit_user_frame(B);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
size_t flatcc_builder_get_current_user_frame(flatcc_builder_t *B) {
|
|
572
|
+
return B->user_frame_offset;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
void *flatcc_builder_get_user_frame_ptr(flatcc_builder_t *B, size_t handle) {
|
|
576
|
+
return us_ptr(handle);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
static int enter_frame(flatcc_builder_t *B, uint16_t align) {
|
|
580
|
+
if (++B->level > B->limit_level) {
|
|
581
|
+
if (B->max_level > 0 && B->level > B->max_level) {
|
|
582
|
+
return -1;
|
|
583
|
+
}
|
|
584
|
+
if (!(B->frame = reserve_buffer(B, flatcc_builder_alloc_fs,
|
|
585
|
+
(size_t)(B->level - 1) * frame_size,
|
|
586
|
+
frame_size, 0))) {
|
|
587
|
+
return -1;
|
|
588
|
+
}
|
|
589
|
+
B->limit_level =
|
|
590
|
+
(int)(B->buffers[flatcc_builder_alloc_fs].iov_len / frame_size);
|
|
591
|
+
if (B->max_level > 0 && B->max_level < B->limit_level) {
|
|
592
|
+
B->limit_level = B->max_level;
|
|
593
|
+
}
|
|
594
|
+
} else {
|
|
595
|
+
++B->frame;
|
|
596
|
+
}
|
|
597
|
+
frame(ds_offset) = B->ds_offset;
|
|
598
|
+
frame(align) = B->align;
|
|
599
|
+
B->align = align;
|
|
600
|
+
/* Note: do not assume padding before first has been allocated! */
|
|
601
|
+
frame(ds_first) = B->ds_first;
|
|
602
|
+
frame(type_limit) = data_limit;
|
|
603
|
+
B->ds_first = alignup_uoffset(B->ds_first + B->ds_offset, 8);
|
|
604
|
+
B->ds_offset = 0;
|
|
605
|
+
return 0;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
static inline void exit_frame(flatcc_builder_t *B) {
|
|
609
|
+
memset(B->ds, 0, B->ds_offset);
|
|
610
|
+
B->ds_offset = frame(ds_offset);
|
|
611
|
+
B->ds_first = frame(ds_first);
|
|
612
|
+
refresh_ds(B, frame(type_limit));
|
|
613
|
+
|
|
614
|
+
/*
|
|
615
|
+
* Restore local alignment: e.g. a table should not change alignment
|
|
616
|
+
* because a child table was just created elsewhere in the buffer,
|
|
617
|
+
* but the overall alignment (min align), should be aware of it.
|
|
618
|
+
* Each buffer has its own min align that then migrates up without
|
|
619
|
+
* being affected by sibling or child buffers.
|
|
620
|
+
*/
|
|
621
|
+
set_min_align(B, B->align);
|
|
622
|
+
B->align = frame(align);
|
|
623
|
+
|
|
624
|
+
--B->frame;
|
|
625
|
+
--B->level;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
static inline uoffset_t front_pad(flatcc_builder_t *B, uoffset_t size,
|
|
629
|
+
uint16_t align) {
|
|
630
|
+
return (uoffset_t)(B->emit_start - (flatcc_builder_ref_t)size) & (align - 1u);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
static inline uoffset_t back_pad(flatcc_builder_t *B, uint16_t align) {
|
|
634
|
+
return (uoffset_t)(B->emit_end) & (align - 1u);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
static inline flatcc_builder_ref_t emit_front(flatcc_builder_t *B,
|
|
638
|
+
iov_state_t *iov) {
|
|
639
|
+
flatcc_builder_ref_t ref;
|
|
640
|
+
|
|
641
|
+
/*
|
|
642
|
+
* We might have overflow when including headers, but without
|
|
643
|
+
* headers we should have checks to prevent overflow in the
|
|
644
|
+
* uoffset_t range, hence we subtract 16 to be safe. With that
|
|
645
|
+
* guarantee we can also make a safe check on the soffset_t range.
|
|
646
|
+
*
|
|
647
|
+
* We only allow buffers half the theoritical size of
|
|
648
|
+
* FLATBUFFERS_UOFFSET_MAX so we can safely use signed references.
|
|
649
|
+
*
|
|
650
|
+
* NOTE: vtables vt_offset field is signed, and the check in create
|
|
651
|
+
* table only ensures the signed limit. The check would fail if the
|
|
652
|
+
* total buffer size could grow beyond UOFFSET_MAX, and we prevent
|
|
653
|
+
* that by limiting the lower end to SOFFSET_MIN, and the upper end
|
|
654
|
+
* at emit_back to SOFFSET_MAX.
|
|
655
|
+
*/
|
|
656
|
+
ref = B->emit_start - (flatcc_builder_ref_t)iov->len;
|
|
657
|
+
if ((iov->len > 16 && iov->len - 16 > FLATBUFFERS_UOFFSET_MAX) ||
|
|
658
|
+
ref >= B->emit_start) {
|
|
659
|
+
check(0, "buffer too large to represent");
|
|
660
|
+
return 0;
|
|
661
|
+
}
|
|
662
|
+
if (B->emit(B->emit_context, iov->iov, iov->count, ref, iov->len)) {
|
|
663
|
+
check(0, "emitter rejected buffer content");
|
|
664
|
+
return 0;
|
|
665
|
+
}
|
|
666
|
+
return B->emit_start = ref;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
static inline flatcc_builder_ref_t emit_back(flatcc_builder_t *B,
|
|
670
|
+
iov_state_t *iov) {
|
|
671
|
+
flatcc_builder_ref_t ref;
|
|
672
|
+
|
|
673
|
+
ref = B->emit_end;
|
|
674
|
+
B->emit_end = ref + (flatcc_builder_ref_t)iov->len;
|
|
675
|
+
/*
|
|
676
|
+
* Similar to emit_front check, but since we only emit vtables and
|
|
677
|
+
* padding at the back, we are not concerned with iov->len overflow,
|
|
678
|
+
* only total buffer overflow.
|
|
679
|
+
*
|
|
680
|
+
* With this check, vtable soffset references at table header can
|
|
681
|
+
* still overflow in extreme cases, so this must be checked
|
|
682
|
+
* separately.
|
|
683
|
+
*/
|
|
684
|
+
if (B->emit_end < ref) {
|
|
685
|
+
check(0, "buffer too large to represent");
|
|
686
|
+
return 0;
|
|
687
|
+
}
|
|
688
|
+
if (B->emit(B->emit_context, iov->iov, iov->count, ref, iov->len)) {
|
|
689
|
+
check(0, "emitter rejected buffer content");
|
|
690
|
+
return 0;
|
|
691
|
+
}
|
|
692
|
+
/*
|
|
693
|
+
* Back references always return ref + 1 because ref == 0 is valid and
|
|
694
|
+
* should not be mistaken for error. vtables understand this.
|
|
695
|
+
*/
|
|
696
|
+
return ref + 1;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
static int align_to_block(flatcc_builder_t *B, uint16_t *align,
|
|
700
|
+
uint16_t block_align, int is_nested) {
|
|
701
|
+
size_t end_pad;
|
|
702
|
+
iov_state_t iov;
|
|
703
|
+
|
|
704
|
+
block_align = block_align ? block_align : B->block_align ? B->block_align : 1;
|
|
705
|
+
get_min_align(align, field_size);
|
|
706
|
+
get_min_align(align, block_align);
|
|
707
|
+
/* Pad end of buffer to multiple. */
|
|
708
|
+
if (!is_nested) {
|
|
709
|
+
end_pad = back_pad(B, block_align);
|
|
710
|
+
if (end_pad) {
|
|
711
|
+
init_iov();
|
|
712
|
+
push_iov(_pad, end_pad);
|
|
713
|
+
if (0 == emit_back(B, &iov)) {
|
|
714
|
+
check(0, "emitter rejected buffer content");
|
|
715
|
+
return -1;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return 0;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B,
|
|
723
|
+
uint16_t block_align,
|
|
724
|
+
const void *data, size_t size,
|
|
725
|
+
uint16_t align, int flags) {
|
|
726
|
+
uoffset_t size_field, pad;
|
|
727
|
+
iov_state_t iov;
|
|
728
|
+
int with_size = flags & flatcc_builder_with_size;
|
|
729
|
+
|
|
730
|
+
if (align_to_block(B, &align, block_align, !is_top_buffer(B))) {
|
|
731
|
+
return 0;
|
|
732
|
+
}
|
|
733
|
+
pad = front_pad(B, (uoffset_t)(size + (with_size ? field_size : 0)), align);
|
|
734
|
+
write_uoffset(&size_field, (uoffset_t)size + pad);
|
|
735
|
+
init_iov();
|
|
736
|
+
/* Add ubyte vector size header if nested buffer. */
|
|
737
|
+
push_iov_cond(&size_field, field_size, !is_top_buffer(B));
|
|
738
|
+
push_iov(data, size);
|
|
739
|
+
push_iov(_pad, pad);
|
|
740
|
+
return emit_front(B, &iov);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
flatcc_builder_ref_t flatcc_builder_create_buffer(
|
|
744
|
+
flatcc_builder_t *B, const char identifier[identifier_size],
|
|
745
|
+
uint16_t block_align, flatcc_builder_ref_t object_ref, uint16_t align,
|
|
746
|
+
int flags) {
|
|
747
|
+
flatcc_builder_ref_t buffer_ref;
|
|
748
|
+
uoffset_t header_pad, id_size = 0;
|
|
749
|
+
uoffset_t object_offset, buffer_size, buffer_base;
|
|
750
|
+
iov_state_t iov;
|
|
751
|
+
flatcc_builder_identifier_t id_out = 0;
|
|
752
|
+
int is_nested = (flags & flatcc_builder_is_nested) != 0;
|
|
753
|
+
int with_size = (flags & flatcc_builder_with_size) != 0;
|
|
754
|
+
|
|
755
|
+
if (align_to_block(B, &align, block_align, is_nested)) {
|
|
756
|
+
return 0;
|
|
757
|
+
}
|
|
758
|
+
set_min_align(B, align);
|
|
759
|
+
if (identifier) {
|
|
760
|
+
FLATCC_ASSERT(sizeof(flatcc_builder_identifier_t) == identifier_size);
|
|
761
|
+
FLATCC_ASSERT(sizeof(flatcc_builder_identifier_t) == field_size);
|
|
762
|
+
memcpy(&id_out, identifier, identifier_size);
|
|
763
|
+
id_out = __flatbuffers_thash_read_from_le(&id_out);
|
|
764
|
+
write_identifier(&id_out, id_out);
|
|
765
|
+
}
|
|
766
|
+
id_size = id_out ? identifier_size : 0;
|
|
767
|
+
header_pad = front_pad(
|
|
768
|
+
B, field_size + id_size + (uoffset_t)(with_size ? field_size : 0), align);
|
|
769
|
+
init_iov();
|
|
770
|
+
/* ubyte vectors size field wrapping nested buffer. */
|
|
771
|
+
push_iov_cond(&buffer_size, field_size, is_nested || with_size);
|
|
772
|
+
push_iov(&object_offset, field_size);
|
|
773
|
+
/* Identifiers are not always present in buffer. */
|
|
774
|
+
push_iov(&id_out, id_size);
|
|
775
|
+
push_iov(_pad, header_pad);
|
|
776
|
+
buffer_base = (uoffset_t)B->emit_start - (uoffset_t)iov.len +
|
|
777
|
+
(uoffset_t)((is_nested || with_size) ? field_size : 0);
|
|
778
|
+
if (is_nested) {
|
|
779
|
+
write_uoffset(&buffer_size, (uoffset_t)B->buffer_mark - buffer_base);
|
|
780
|
+
} else {
|
|
781
|
+
/* Also include clustered vtables. */
|
|
782
|
+
write_uoffset(&buffer_size, (uoffset_t)B->emit_end - buffer_base);
|
|
783
|
+
}
|
|
784
|
+
write_uoffset(&object_offset, (uoffset_t)object_ref - buffer_base);
|
|
785
|
+
if (0 == (buffer_ref = emit_front(B, &iov))) {
|
|
786
|
+
check(0, "emitter rejected buffer content");
|
|
787
|
+
return 0;
|
|
788
|
+
}
|
|
789
|
+
return buffer_ref;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
flatcc_builder_ref_t flatcc_builder_create_struct(flatcc_builder_t *B,
|
|
793
|
+
const void *data, size_t size,
|
|
794
|
+
uint16_t align) {
|
|
795
|
+
size_t pad;
|
|
796
|
+
iov_state_t iov;
|
|
797
|
+
|
|
798
|
+
check(align >= 1, "align cannot be 0");
|
|
799
|
+
set_min_align(B, align);
|
|
800
|
+
pad = front_pad(B, (uoffset_t)size, align);
|
|
801
|
+
init_iov();
|
|
802
|
+
push_iov(data, size);
|
|
803
|
+
/*
|
|
804
|
+
* Normally structs will already be a multiple of their alignment,
|
|
805
|
+
* so this padding will not likely be emitted.
|
|
806
|
+
*/
|
|
807
|
+
push_iov(_pad, pad);
|
|
808
|
+
return emit_front(B, &iov);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
int flatcc_builder_start_buffer(flatcc_builder_t *B,
|
|
812
|
+
const char identifier[identifier_size],
|
|
813
|
+
uint16_t block_align, int flags) {
|
|
814
|
+
/*
|
|
815
|
+
* This saves the parent `min_align` in the align field since we
|
|
816
|
+
* shouldn't use that for the current buffer. `exit_frame`
|
|
817
|
+
* automatically aggregates align up, so it is updated when the
|
|
818
|
+
* buffer frame exits.
|
|
819
|
+
*/
|
|
820
|
+
if (enter_frame(B, B->min_align)) {
|
|
821
|
+
return -1;
|
|
822
|
+
}
|
|
823
|
+
/* B->align now has parent min_align, and child frames will save it. */
|
|
824
|
+
B->min_align = 1;
|
|
825
|
+
/* Save the parent block align, and set proper defaults for this buffer. */
|
|
826
|
+
frame(container.buffer.block_align) = B->block_align;
|
|
827
|
+
B->block_align = block_align;
|
|
828
|
+
frame(container.buffer.flags = B->buffer_flags);
|
|
829
|
+
B->buffer_flags = (uint16_t)flags;
|
|
830
|
+
frame(container.buffer.mark) = B->buffer_mark;
|
|
831
|
+
frame(container.buffer.nest_id) = B->nest_id;
|
|
832
|
+
/*
|
|
833
|
+
* End of buffer when nested. Not defined for top-level because we
|
|
834
|
+
* here (on only here) permit strings etc. to be created before buffer start
|
|
835
|
+
* and because top-level buffer vtables can be clustered.
|
|
836
|
+
*/
|
|
837
|
+
B->buffer_mark = B->emit_start;
|
|
838
|
+
/* Must be 0 before and after entering top-level buffer, and unique otherwise.
|
|
839
|
+
*/
|
|
840
|
+
B->nest_id = B->nest_count++;
|
|
841
|
+
frame(container.buffer.identifier) = B->identifier;
|
|
842
|
+
set_identifier(identifier);
|
|
843
|
+
frame(type) = flatcc_builder_buffer;
|
|
844
|
+
return 0;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B,
|
|
848
|
+
flatcc_builder_ref_t root) {
|
|
849
|
+
flatcc_builder_ref_t buffer_ref;
|
|
850
|
+
int flags;
|
|
851
|
+
|
|
852
|
+
flags = B->buffer_flags & flatcc_builder_with_size;
|
|
853
|
+
flags |= is_top_buffer(B) ? 0 : flatcc_builder_is_nested;
|
|
854
|
+
check(frame(type) == flatcc_builder_buffer, "expected buffer frame");
|
|
855
|
+
set_min_align(B, B->block_align);
|
|
856
|
+
if (0 == (buffer_ref = flatcc_builder_create_buffer(B, (void *)&B->identifier,
|
|
857
|
+
B->block_align, root,
|
|
858
|
+
B->min_align, flags))) {
|
|
859
|
+
return 0;
|
|
860
|
+
}
|
|
861
|
+
B->buffer_mark = frame(container.buffer.mark);
|
|
862
|
+
B->nest_id = frame(container.buffer.nest_id);
|
|
863
|
+
B->identifier = frame(container.buffer.identifier);
|
|
864
|
+
B->buffer_flags = frame(container.buffer.flags);
|
|
865
|
+
exit_frame(B);
|
|
866
|
+
return buffer_ref;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
void *flatcc_builder_start_struct(flatcc_builder_t *B, size_t size,
|
|
870
|
+
uint16_t align) {
|
|
871
|
+
/* Allocate space for the struct on the ds stack. */
|
|
872
|
+
if (enter_frame(B, align)) {
|
|
873
|
+
return 0;
|
|
874
|
+
}
|
|
875
|
+
frame(type) = flatcc_builder_struct;
|
|
876
|
+
refresh_ds(B, data_limit);
|
|
877
|
+
return push_ds(B, (uoffset_t)size);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
void *flatcc_builder_struct_edit(flatcc_builder_t *B) { return B->ds; }
|
|
881
|
+
|
|
882
|
+
flatcc_builder_ref_t flatcc_builder_end_struct(flatcc_builder_t *B) {
|
|
883
|
+
flatcc_builder_ref_t object_ref;
|
|
884
|
+
|
|
885
|
+
check(frame(type) == flatcc_builder_struct, "expected struct frame");
|
|
886
|
+
if (0 == (object_ref = flatcc_builder_create_struct(B, B->ds, B->ds_offset,
|
|
887
|
+
B->align))) {
|
|
888
|
+
return 0;
|
|
889
|
+
}
|
|
890
|
+
exit_frame(B);
|
|
891
|
+
return object_ref;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
static inline int vector_count_add(flatcc_builder_t *B, uoffset_t count,
|
|
895
|
+
uoffset_t max_count) {
|
|
896
|
+
uoffset_t n, n1;
|
|
897
|
+
n = frame(container.vector.count);
|
|
898
|
+
n1 = n + count;
|
|
899
|
+
/*
|
|
900
|
+
* This prevents elem_size * count from overflowing iff max_vector
|
|
901
|
+
* has been set sensible. Without this check we might allocate to
|
|
902
|
+
* little on the ds stack and return a buffer the user thinks is
|
|
903
|
+
* much larger which of course is bad even though the buffer eventually
|
|
904
|
+
* would fail anyway.
|
|
905
|
+
*/
|
|
906
|
+
check_error(n <= n1 && n1 <= max_count, -1, "vector too large to represent");
|
|
907
|
+
frame(container.vector.count) = n1;
|
|
908
|
+
return 0;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
void *flatcc_builder_extend_vector(flatcc_builder_t *B, size_t count) {
|
|
912
|
+
if (vector_count_add(B, (uoffset_t)count,
|
|
913
|
+
frame(container.vector.max_count))) {
|
|
914
|
+
return 0;
|
|
915
|
+
}
|
|
916
|
+
return push_ds(B, frame(container.vector.elem_size) * (uoffset_t)count);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
void *flatcc_builder_vector_push(flatcc_builder_t *B, const void *data) {
|
|
920
|
+
check(frame(type) == flatcc_builder_vector, "expected vector frame");
|
|
921
|
+
check_error(
|
|
922
|
+
frame(container.vector.count) <= frame(container.vector.max_count), 0,
|
|
923
|
+
"vector max count exceeded");
|
|
924
|
+
frame(container.vector.count) += 1;
|
|
925
|
+
return push_ds_copy(B, data, frame(container.vector.elem_size));
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
void *flatcc_builder_append_vector(flatcc_builder_t *B, const void *data,
|
|
929
|
+
size_t count) {
|
|
930
|
+
check(frame(type) == flatcc_builder_vector, "expected vector frame");
|
|
931
|
+
if (vector_count_add(B, (uoffset_t)count,
|
|
932
|
+
frame(container.vector.max_count))) {
|
|
933
|
+
return 0;
|
|
934
|
+
}
|
|
935
|
+
return push_ds_copy(B, data,
|
|
936
|
+
frame(container.vector.elem_size) * (uoffset_t)count);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
flatcc_builder_ref_t *flatcc_builder_extend_offset_vector(flatcc_builder_t *B,
|
|
940
|
+
size_t count) {
|
|
941
|
+
if (vector_count_add(B, (uoffset_t)count, max_offset_count)) {
|
|
942
|
+
return 0;
|
|
943
|
+
}
|
|
944
|
+
return push_ds(B, (uoffset_t)(field_size * count));
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
flatcc_builder_ref_t *flatcc_builder_offset_vector_push(
|
|
948
|
+
flatcc_builder_t *B, flatcc_builder_ref_t ref) {
|
|
949
|
+
flatcc_builder_ref_t *p;
|
|
950
|
+
|
|
951
|
+
check(frame(type) == flatcc_builder_offset_vector,
|
|
952
|
+
"expected offset vector frame");
|
|
953
|
+
if (frame(container.vector.count) == max_offset_count) {
|
|
954
|
+
return 0;
|
|
955
|
+
}
|
|
956
|
+
frame(container.vector.count) += 1;
|
|
957
|
+
if (0 == (p = push_ds(B, field_size))) {
|
|
958
|
+
return 0;
|
|
959
|
+
}
|
|
960
|
+
*p = ref;
|
|
961
|
+
return p;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
flatcc_builder_ref_t *flatcc_builder_append_offset_vector(
|
|
965
|
+
flatcc_builder_t *B, const flatcc_builder_ref_t *refs, size_t count) {
|
|
966
|
+
check(frame(type) == flatcc_builder_offset_vector,
|
|
967
|
+
"expected offset vector frame");
|
|
968
|
+
if (vector_count_add(B, (uoffset_t)count, max_offset_count)) {
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
return push_ds_copy(B, refs, (uoffset_t)(field_size * count));
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
char *flatcc_builder_extend_string(flatcc_builder_t *B, size_t len) {
|
|
975
|
+
check(frame(type) == flatcc_builder_string, "expected string frame");
|
|
976
|
+
if (vector_count_add(B, (uoffset_t)len, max_string_len)) {
|
|
977
|
+
return 0;
|
|
978
|
+
}
|
|
979
|
+
return push_ds(B, (uoffset_t)len);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
char *flatcc_builder_append_string(flatcc_builder_t *B, const char *s,
|
|
983
|
+
size_t len) {
|
|
984
|
+
check(frame(type) == flatcc_builder_string, "expected string frame");
|
|
985
|
+
if (vector_count_add(B, (uoffset_t)len, max_string_len)) {
|
|
986
|
+
return 0;
|
|
987
|
+
}
|
|
988
|
+
return push_ds_copy(B, s, (uoffset_t)len);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
char *flatcc_builder_append_string_str(flatcc_builder_t *B, const char *s) {
|
|
992
|
+
return flatcc_builder_append_string(B, s, strlen(s));
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
char *flatcc_builder_append_string_strn(flatcc_builder_t *B, const char *s,
|
|
996
|
+
size_t max_len) {
|
|
997
|
+
return flatcc_builder_append_string(B, s, strnlen(s, max_len));
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
int flatcc_builder_truncate_vector(flatcc_builder_t *B, size_t count) {
|
|
1001
|
+
check(frame(type) == flatcc_builder_vector, "expected vector frame");
|
|
1002
|
+
check_error(frame(container.vector.count) >= count, -1,
|
|
1003
|
+
"cannot truncate vector past empty");
|
|
1004
|
+
frame(container.vector.count) -= (uoffset_t)count;
|
|
1005
|
+
unpush_ds(B, frame(container.vector.elem_size) * (uoffset_t)count);
|
|
1006
|
+
return 0;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
int flatcc_builder_truncate_offset_vector(flatcc_builder_t *B, size_t count) {
|
|
1010
|
+
check(frame(type) == flatcc_builder_offset_vector,
|
|
1011
|
+
"expected offset vector frame");
|
|
1012
|
+
check_error(frame(container.vector.count) >= (uoffset_t)count, -1,
|
|
1013
|
+
"cannot truncate vector past empty");
|
|
1014
|
+
frame(container.vector.count) -= (uoffset_t)count;
|
|
1015
|
+
unpush_ds(B, frame(container.vector.elem_size) * (uoffset_t)count);
|
|
1016
|
+
return 0;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
int flatcc_builder_truncate_string(flatcc_builder_t *B, size_t len) {
|
|
1020
|
+
check(frame(type) == flatcc_builder_string, "expected string frame");
|
|
1021
|
+
check_error(frame(container.vector.count) >= len, -1,
|
|
1022
|
+
"cannot truncate string past empty");
|
|
1023
|
+
frame(container.vector.count) -= (uoffset_t)len;
|
|
1024
|
+
unpush_ds(B, (uoffset_t)len);
|
|
1025
|
+
return 0;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
int flatcc_builder_start_vector(flatcc_builder_t *B, size_t elem_size,
|
|
1029
|
+
uint16_t align, size_t max_count) {
|
|
1030
|
+
get_min_align(&align, field_size);
|
|
1031
|
+
if (enter_frame(B, align)) {
|
|
1032
|
+
return -1;
|
|
1033
|
+
}
|
|
1034
|
+
frame(container.vector.elem_size) = (uoffset_t)elem_size;
|
|
1035
|
+
frame(container.vector.count) = 0;
|
|
1036
|
+
frame(container.vector.max_count) = (uoffset_t)max_count;
|
|
1037
|
+
frame(type) = flatcc_builder_vector;
|
|
1038
|
+
refresh_ds(B, data_limit);
|
|
1039
|
+
return 0;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
int flatcc_builder_start_offset_vector(flatcc_builder_t *B) {
|
|
1043
|
+
if (enter_frame(B, field_size)) {
|
|
1044
|
+
return -1;
|
|
1045
|
+
}
|
|
1046
|
+
frame(container.vector.elem_size) = field_size;
|
|
1047
|
+
frame(container.vector.count) = 0;
|
|
1048
|
+
frame(type) = flatcc_builder_offset_vector;
|
|
1049
|
+
refresh_ds(B, data_limit);
|
|
1050
|
+
return 0;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
flatcc_builder_ref_t flatcc_builder_create_offset_vector(
|
|
1054
|
+
flatcc_builder_t *B, const flatcc_builder_ref_t *vec, size_t count) {
|
|
1055
|
+
flatcc_builder_ref_t *_vec;
|
|
1056
|
+
|
|
1057
|
+
if (flatcc_builder_start_offset_vector(B)) {
|
|
1058
|
+
return 0;
|
|
1059
|
+
}
|
|
1060
|
+
if (!(_vec = flatcc_builder_extend_offset_vector(B, count))) {
|
|
1061
|
+
return 0;
|
|
1062
|
+
}
|
|
1063
|
+
memcpy(_vec, vec, count * field_size);
|
|
1064
|
+
return flatcc_builder_end_offset_vector(B);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
int flatcc_builder_start_string(flatcc_builder_t *B) {
|
|
1068
|
+
if (enter_frame(B, 1)) {
|
|
1069
|
+
return -1;
|
|
1070
|
+
}
|
|
1071
|
+
frame(container.vector.elem_size) = 1;
|
|
1072
|
+
frame(container.vector.count) = 0;
|
|
1073
|
+
frame(type) = flatcc_builder_string;
|
|
1074
|
+
refresh_ds(B, data_limit);
|
|
1075
|
+
return 0;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
int flatcc_builder_reserve_table(flatcc_builder_t *B, int count) {
|
|
1079
|
+
check(count >= 0, "cannot reserve negative count");
|
|
1080
|
+
return reserve_fields(B, count);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
int flatcc_builder_start_table(flatcc_builder_t *B, int count) {
|
|
1084
|
+
if (enter_frame(B, field_size)) {
|
|
1085
|
+
return -1;
|
|
1086
|
+
}
|
|
1087
|
+
frame(container.table.vs_end) = vs_offset(B->vs);
|
|
1088
|
+
frame(container.table.pl_end) = pl_offset(B->pl);
|
|
1089
|
+
frame(container.table.vt_hash) = B->vt_hash;
|
|
1090
|
+
frame(container.table.id_end) = B->id_end;
|
|
1091
|
+
B->vt_hash = 0;
|
|
1092
|
+
FLATCC_BUILDER_INIT_VT_HASH(B->vt_hash);
|
|
1093
|
+
B->id_end = 0;
|
|
1094
|
+
frame(type) = flatcc_builder_table;
|
|
1095
|
+
if (reserve_fields(B, count)) {
|
|
1096
|
+
return -1;
|
|
1097
|
+
}
|
|
1098
|
+
refresh_ds(B, table_limit);
|
|
1099
|
+
return 0;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
flatcc_builder_vt_ref_t flatcc_builder_create_vtable(flatcc_builder_t *B,
|
|
1103
|
+
const voffset_t *vt,
|
|
1104
|
+
voffset_t vt_size) {
|
|
1105
|
+
flatcc_builder_vt_ref_t vt_ref;
|
|
1106
|
+
iov_state_t iov;
|
|
1107
|
+
voffset_t *vt_;
|
|
1108
|
+
size_t i;
|
|
1109
|
+
|
|
1110
|
+
/*
|
|
1111
|
+
* Only top-level buffer can cluster vtables because only it can
|
|
1112
|
+
* extend beyond the end.
|
|
1113
|
+
*
|
|
1114
|
+
* We write the vtable after the referencing table to maintain
|
|
1115
|
+
* the construction invariant that any offset reference has
|
|
1116
|
+
* valid emitted data at a higher address, and also that any
|
|
1117
|
+
* issued negative emit address represents an offset reference
|
|
1118
|
+
* to some flatbuffer object or vector (or possibly a root
|
|
1119
|
+
* struct).
|
|
1120
|
+
*
|
|
1121
|
+
* The vt_ref is stored as the reference + 1 to avoid having 0 as a
|
|
1122
|
+
* valid reference (which usally means error). It also idententifies
|
|
1123
|
+
* vtable references as the only uneven references, and the only
|
|
1124
|
+
* references that can be used multiple times in the same buffer.
|
|
1125
|
+
*
|
|
1126
|
+
* We do the vtable conversion here so cached vtables can be built
|
|
1127
|
+
* hashed and compared more efficiently, and so end users with
|
|
1128
|
+
* direct vtable construction don't have to worry about endianness.
|
|
1129
|
+
* This also ensures the hash function works the same wrt.
|
|
1130
|
+
* collision frequency.
|
|
1131
|
+
*/
|
|
1132
|
+
|
|
1133
|
+
if (!flatbuffers_is_native_pe()) {
|
|
1134
|
+
/* Make space in vtable cache for temporary endian conversion. */
|
|
1135
|
+
if (!(vt_ = reserve_buffer(B, flatcc_builder_alloc_vb, B->vb_end, vt_size,
|
|
1136
|
+
0))) {
|
|
1137
|
+
return 0;
|
|
1138
|
+
}
|
|
1139
|
+
for (i = 0; i < vt_size / sizeof(voffset_t); ++i) {
|
|
1140
|
+
write_voffset(&vt_[i], vt[i]);
|
|
1141
|
+
}
|
|
1142
|
+
vt = vt_;
|
|
1143
|
+
/* We don't need to free the reservation since we don't advance any base
|
|
1144
|
+
* pointer. */
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
init_iov();
|
|
1148
|
+
push_iov(vt, vt_size);
|
|
1149
|
+
if (is_top_buffer(B) && !B->disable_vt_clustering) {
|
|
1150
|
+
/* Note that `emit_back` already returns ref + 1 as we require for vtables.
|
|
1151
|
+
*/
|
|
1152
|
+
if (0 == (vt_ref = emit_back(B, &iov))) {
|
|
1153
|
+
return 0;
|
|
1154
|
+
}
|
|
1155
|
+
} else {
|
|
1156
|
+
if (0 == (vt_ref = emit_front(B, &iov))) {
|
|
1157
|
+
return 0;
|
|
1158
|
+
}
|
|
1159
|
+
/*
|
|
1160
|
+
* We don't have a valid 0 ref here, but to be consistent with
|
|
1161
|
+
* clustered vtables we offset by one. This cannot be zero
|
|
1162
|
+
* either.
|
|
1163
|
+
*/
|
|
1164
|
+
vt_ref += 1;
|
|
1165
|
+
}
|
|
1166
|
+
return vt_ref;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
flatcc_builder_vt_ref_t flatcc_builder_create_cached_vtable(flatcc_builder_t *B,
|
|
1170
|
+
const voffset_t *vt,
|
|
1171
|
+
voffset_t vt_size,
|
|
1172
|
+
uint32_t vt_hash) {
|
|
1173
|
+
vtable_descriptor_t *vd, *vd2;
|
|
1174
|
+
uoffset_t *pvd, *pvd_head;
|
|
1175
|
+
uoffset_t next;
|
|
1176
|
+
voffset_t *vt_;
|
|
1177
|
+
|
|
1178
|
+
/* This just gets the hash table slot, we still have to inspect it. */
|
|
1179
|
+
if (!(pvd_head = lookup_ht(B, vt_hash))) {
|
|
1180
|
+
return 0;
|
|
1181
|
+
}
|
|
1182
|
+
pvd = pvd_head;
|
|
1183
|
+
next = *pvd;
|
|
1184
|
+
/* Tracks if there already is a cached copy. */
|
|
1185
|
+
vd2 = 0;
|
|
1186
|
+
while (next) {
|
|
1187
|
+
vd = vd_ptr(next);
|
|
1188
|
+
vt_ = vb_ptr(vd->vb_start);
|
|
1189
|
+
if (vt_[0] != vt_size || 0 != memcmp(vt, vt_, vt_size)) {
|
|
1190
|
+
pvd = &vd->next;
|
|
1191
|
+
next = vd->next;
|
|
1192
|
+
continue;
|
|
1193
|
+
}
|
|
1194
|
+
/* Can't share emitted vtables between buffers, */
|
|
1195
|
+
if (vd->nest_id != B->nest_id) {
|
|
1196
|
+
/* but we don't have to resubmit to cache. */
|
|
1197
|
+
vd2 = vd;
|
|
1198
|
+
/* See if there is a better match. */
|
|
1199
|
+
pvd = &vd->next;
|
|
1200
|
+
next = vd->next;
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
/* Move to front hash strategy. */
|
|
1204
|
+
if (pvd != pvd_head) {
|
|
1205
|
+
*pvd = vd->next;
|
|
1206
|
+
vd->next = *pvd_head;
|
|
1207
|
+
*pvd_head = next;
|
|
1208
|
+
}
|
|
1209
|
+
/* vtable exists and has been emitted within current buffer. */
|
|
1210
|
+
return vd->vt_ref;
|
|
1211
|
+
}
|
|
1212
|
+
/* Allocate new descriptor. */
|
|
1213
|
+
if (!(vd = reserve_buffer(B, flatcc_builder_alloc_vd, B->vd_end,
|
|
1214
|
+
sizeof(vtable_descriptor_t), 0))) {
|
|
1215
|
+
return 0;
|
|
1216
|
+
}
|
|
1217
|
+
next = B->vd_end;
|
|
1218
|
+
B->vd_end += (uoffset_t)sizeof(vtable_descriptor_t);
|
|
1219
|
+
|
|
1220
|
+
/* Identify the buffer this vtable descriptor belongs to. */
|
|
1221
|
+
vd->nest_id = B->nest_id;
|
|
1222
|
+
|
|
1223
|
+
/* Move to front hash strategy. */
|
|
1224
|
+
vd->next = *pvd_head;
|
|
1225
|
+
*pvd_head = next;
|
|
1226
|
+
if (0 == (vd->vt_ref = flatcc_builder_create_vtable(B, vt, vt_size))) {
|
|
1227
|
+
return 0;
|
|
1228
|
+
}
|
|
1229
|
+
if (vd2) {
|
|
1230
|
+
/* Reuse cached copy. */
|
|
1231
|
+
vd->vb_start = vd2->vb_start;
|
|
1232
|
+
} else {
|
|
1233
|
+
if (B->vb_flush_limit && B->vb_flush_limit < B->vb_end + vt_size) {
|
|
1234
|
+
flatcc_builder_flush_vtable_cache(B);
|
|
1235
|
+
} else {
|
|
1236
|
+
/* Make space in vtable cache. */
|
|
1237
|
+
if (!(vt_ = reserve_buffer(B, flatcc_builder_alloc_vb, B->vb_end, vt_size,
|
|
1238
|
+
0))) {
|
|
1239
|
+
return -1;
|
|
1240
|
+
}
|
|
1241
|
+
vd->vb_start = B->vb_end;
|
|
1242
|
+
B->vb_end += vt_size;
|
|
1243
|
+
memcpy(vt_, vt, vt_size);
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return vd->vt_ref;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
flatcc_builder_ref_t flatcc_builder_create_table(
|
|
1250
|
+
flatcc_builder_t *B, const void *data, size_t size, uint16_t align,
|
|
1251
|
+
flatbuffers_voffset_t *offsets, int offset_count,
|
|
1252
|
+
flatcc_builder_vt_ref_t vt_ref) {
|
|
1253
|
+
int i;
|
|
1254
|
+
uoffset_t pad, vt_offset, vt_offset_field, vt_base, base, offset,
|
|
1255
|
+
*offset_field;
|
|
1256
|
+
iov_state_t iov;
|
|
1257
|
+
|
|
1258
|
+
check(offset_count >= 0, "expected non-negative offset_count");
|
|
1259
|
+
/*
|
|
1260
|
+
* vtable references are offset by 1 to avoid confusion with
|
|
1261
|
+
* 0 as an error reference. It also uniquely identifies them
|
|
1262
|
+
* as vtables being the only uneven reference type.
|
|
1263
|
+
*/
|
|
1264
|
+
check(vt_ref & 1, "invalid vtable referenc");
|
|
1265
|
+
get_min_align(&align, field_size);
|
|
1266
|
+
set_min_align(B, align);
|
|
1267
|
+
/* Alignment is calculated for the first element, not the header. */
|
|
1268
|
+
pad = front_pad(B, (uoffset_t)size, align);
|
|
1269
|
+
base = (uoffset_t)B->emit_start - (uoffset_t)(pad + size + field_size);
|
|
1270
|
+
/* Adjust by 1 to get unencoded vtable reference. */
|
|
1271
|
+
vt_base = (uoffset_t)(vt_ref - 1);
|
|
1272
|
+
vt_offset = base - vt_base;
|
|
1273
|
+
/* Avoid overflow. */
|
|
1274
|
+
if (base - vt_offset != vt_base) {
|
|
1275
|
+
return -1;
|
|
1276
|
+
}
|
|
1277
|
+
/* Protocol endian encoding. */
|
|
1278
|
+
write_uoffset(&vt_offset_field, vt_offset);
|
|
1279
|
+
for (i = 0; i < offset_count; ++i) {
|
|
1280
|
+
offset_field = (uoffset_t *)((size_t)data + offsets[i]);
|
|
1281
|
+
offset = *offset_field - base - offsets[i] - (uoffset_t)field_size;
|
|
1282
|
+
write_uoffset(offset_field, offset);
|
|
1283
|
+
}
|
|
1284
|
+
init_iov();
|
|
1285
|
+
push_iov(&vt_offset_field, field_size);
|
|
1286
|
+
push_iov(data, size);
|
|
1287
|
+
push_iov(_pad, pad);
|
|
1288
|
+
return emit_front(B, &iov);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
int flatcc_builder_check_required_field(flatcc_builder_t *B,
|
|
1292
|
+
flatbuffers_voffset_t id) {
|
|
1293
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1294
|
+
|
|
1295
|
+
return id < B->id_end && B->vs[id] != 0;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
int flatcc_builder_check_union_field(flatcc_builder_t *B,
|
|
1299
|
+
flatbuffers_voffset_t id) {
|
|
1300
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1301
|
+
|
|
1302
|
+
if (id == 0 || id >= B->id_end) {
|
|
1303
|
+
return 0;
|
|
1304
|
+
}
|
|
1305
|
+
if (B->vs[id - 1] == 0) {
|
|
1306
|
+
return B->vs[id] == 0;
|
|
1307
|
+
}
|
|
1308
|
+
if (*(uint8_t *)(B->ds + B->vs[id - 1])) {
|
|
1309
|
+
return B->vs[id] != 0;
|
|
1310
|
+
}
|
|
1311
|
+
return B->vs[id] == 0;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
int flatcc_builder_check_required(flatcc_builder_t *B,
|
|
1315
|
+
const flatbuffers_voffset_t *required,
|
|
1316
|
+
int count) {
|
|
1317
|
+
int i;
|
|
1318
|
+
|
|
1319
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1320
|
+
|
|
1321
|
+
if (B->id_end < count) {
|
|
1322
|
+
return 0;
|
|
1323
|
+
}
|
|
1324
|
+
for (i = 0; i < count; ++i) {
|
|
1325
|
+
if (B->vs[required[i]] == 0) {
|
|
1326
|
+
return 0;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return 1;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B) {
|
|
1333
|
+
voffset_t *vt, vt_size;
|
|
1334
|
+
flatcc_builder_ref_t table_ref, vt_ref;
|
|
1335
|
+
int pl_count;
|
|
1336
|
+
voffset_t *pl;
|
|
1337
|
+
|
|
1338
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1339
|
+
|
|
1340
|
+
/* We have `ds_limit`, so we should not have to check for overflow here. */
|
|
1341
|
+
|
|
1342
|
+
vt = B->vs - 2;
|
|
1343
|
+
vt_size = (voffset_t)(sizeof(voffset_t) * (B->id_end + 2u));
|
|
1344
|
+
/* Update vtable header fields, first vtable size, then object table size. */
|
|
1345
|
+
vt[0] = vt_size;
|
|
1346
|
+
/*
|
|
1347
|
+
* The `ds` buffer is always at least `field_size` aligned but excludes the
|
|
1348
|
+
* initial vtable offset field. Therefore `field_size` is added here
|
|
1349
|
+
* to the total table size in the vtable.
|
|
1350
|
+
*/
|
|
1351
|
+
vt[1] = (voffset_t)(B->ds_offset + field_size);
|
|
1352
|
+
FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)vt[0], (uint32_t)vt[1]);
|
|
1353
|
+
/* Find already emitted vtable, or emit a new one. */
|
|
1354
|
+
if (!(vt_ref =
|
|
1355
|
+
flatcc_builder_create_cached_vtable(B, vt, vt_size, B->vt_hash))) {
|
|
1356
|
+
return 0;
|
|
1357
|
+
}
|
|
1358
|
+
/* Clear vs stack so it is ready for the next vtable (ds stack is cleared by
|
|
1359
|
+
* exit frame). */
|
|
1360
|
+
memset(vt, 0, vt_size);
|
|
1361
|
+
|
|
1362
|
+
pl = pl_ptr(frame(container.table.pl_end));
|
|
1363
|
+
pl_count = (int)(B->pl - pl);
|
|
1364
|
+
if (0 == (table_ref = flatcc_builder_create_table(
|
|
1365
|
+
B, B->ds, B->ds_offset, B->align, pl, pl_count, vt_ref))) {
|
|
1366
|
+
return 0;
|
|
1367
|
+
}
|
|
1368
|
+
B->vt_hash = frame(container.table.vt_hash);
|
|
1369
|
+
B->id_end = frame(container.table.id_end);
|
|
1370
|
+
B->vs = vs_ptr(frame(container.table.vs_end));
|
|
1371
|
+
B->pl = pl_ptr(frame(container.table.pl_end));
|
|
1372
|
+
exit_frame(B);
|
|
1373
|
+
return table_ref;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
flatcc_builder_ref_t flatcc_builder_create_vector(
|
|
1377
|
+
flatcc_builder_t *B, const void *data, size_t count, size_t elem_size,
|
|
1378
|
+
uint16_t align, size_t max_count) {
|
|
1379
|
+
/*
|
|
1380
|
+
* Note: it is important that vec_size is uoffset not size_t
|
|
1381
|
+
* in case sizeof(uoffset_t) > sizeof(size_t) because max_count is
|
|
1382
|
+
* defined in terms of uoffset_t representation size, and also
|
|
1383
|
+
* because we risk accepting too large a vector even if max_count is
|
|
1384
|
+
* not violated.
|
|
1385
|
+
*/
|
|
1386
|
+
uoffset_t vec_size, vec_pad, length_prefix;
|
|
1387
|
+
iov_state_t iov;
|
|
1388
|
+
|
|
1389
|
+
check_error(count <= max_count, 0, "vector max_count violated");
|
|
1390
|
+
get_min_align(&align, field_size);
|
|
1391
|
+
set_min_align(B, align);
|
|
1392
|
+
vec_size = (uoffset_t)count * (uoffset_t)elem_size;
|
|
1393
|
+
/*
|
|
1394
|
+
* That can happen on 32 bit systems when uoffset_t is defined as 64-bit.
|
|
1395
|
+
* `emit_front/back` captures overflow, but not if our size type wraps first.
|
|
1396
|
+
*/
|
|
1397
|
+
#if FLATBUFFERS_UOFFSET_MAX > SIZE_MAX
|
|
1398
|
+
check_error(vec_size < SIZE_MAX, 0, "vector larger than address space");
|
|
1399
|
+
#endif
|
|
1400
|
+
write_uoffset(&length_prefix, (uoffset_t)count);
|
|
1401
|
+
/* Alignment is calculated for the first element, not the header. */
|
|
1402
|
+
vec_pad = front_pad(B, vec_size, align);
|
|
1403
|
+
init_iov();
|
|
1404
|
+
push_iov(&length_prefix, field_size);
|
|
1405
|
+
push_iov(data, vec_size);
|
|
1406
|
+
push_iov(_pad, vec_pad);
|
|
1407
|
+
return emit_front(B, &iov);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/*
|
|
1411
|
+
* Note: FlatBuffers official documentation states that the size field of a
|
|
1412
|
+
* vector is a 32-bit element count. It is not quite clear if the
|
|
1413
|
+
* intention is to have the size field be of type uoffset_t since tables
|
|
1414
|
+
* also have a uoffset_t sized header, or if the vector size should
|
|
1415
|
+
* remain unchanged if uoffset is changed to 16- or 64-bits
|
|
1416
|
+
* respectively. Since it makes most sense to have a vector compatible
|
|
1417
|
+
* with the addressable space, we choose to use uoffset_t as size field,
|
|
1418
|
+
* which remains compatible with the default 32-bit version of uoffset_t.
|
|
1419
|
+
*/
|
|
1420
|
+
flatcc_builder_ref_t flatcc_builder_end_vector(flatcc_builder_t *B) {
|
|
1421
|
+
flatcc_builder_ref_t vector_ref;
|
|
1422
|
+
|
|
1423
|
+
check(frame(type) == flatcc_builder_vector, "expected vector frame");
|
|
1424
|
+
|
|
1425
|
+
if (0 == (vector_ref = flatcc_builder_create_vector(
|
|
1426
|
+
B, B->ds, frame(container.vector.count),
|
|
1427
|
+
frame(container.vector.elem_size), B->align,
|
|
1428
|
+
frame(container.vector.max_count)))) {
|
|
1429
|
+
return 0;
|
|
1430
|
+
}
|
|
1431
|
+
exit_frame(B);
|
|
1432
|
+
return vector_ref;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
size_t flatcc_builder_vector_count(flatcc_builder_t *B) {
|
|
1436
|
+
return frame(container.vector.count);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
void *flatcc_builder_vector_edit(flatcc_builder_t *B) { return B->ds; }
|
|
1440
|
+
|
|
1441
|
+
/* This function destroys the source content but avoids stack allocation. */
|
|
1442
|
+
static flatcc_builder_ref_t _create_offset_vector_direct(
|
|
1443
|
+
flatcc_builder_t *B, flatcc_builder_ref_t *vec, size_t count,
|
|
1444
|
+
const utype_t *types) {
|
|
1445
|
+
uoffset_t vec_size, vec_pad;
|
|
1446
|
+
uoffset_t length_prefix, offset;
|
|
1447
|
+
uoffset_t i;
|
|
1448
|
+
soffset_t base;
|
|
1449
|
+
iov_state_t iov;
|
|
1450
|
+
|
|
1451
|
+
if ((uoffset_t)count > max_offset_count) {
|
|
1452
|
+
return 0;
|
|
1453
|
+
}
|
|
1454
|
+
set_min_align(B, field_size);
|
|
1455
|
+
vec_size = (uoffset_t)(count * field_size);
|
|
1456
|
+
write_uoffset(&length_prefix, (uoffset_t)count);
|
|
1457
|
+
/* Alignment is calculated for the first element, not the header. */
|
|
1458
|
+
vec_pad = front_pad(B, vec_size, field_size);
|
|
1459
|
+
init_iov();
|
|
1460
|
+
push_iov(&length_prefix, field_size);
|
|
1461
|
+
push_iov(vec, vec_size);
|
|
1462
|
+
push_iov(_pad, vec_pad);
|
|
1463
|
+
base = B->emit_start - (soffset_t)iov.len;
|
|
1464
|
+
for (i = 0; i < (uoffset_t)count; ++i) {
|
|
1465
|
+
/*
|
|
1466
|
+
* 0 is either end of buffer, start of vtables, or start of
|
|
1467
|
+
* buffer depending on the direction in which the buffer is
|
|
1468
|
+
* built. None of these can create a valid 0 reference but it
|
|
1469
|
+
* is easy to create by mistake when manually building offset
|
|
1470
|
+
* vectors.
|
|
1471
|
+
*
|
|
1472
|
+
* Unions do permit nulls, but only when the type is NONE.
|
|
1473
|
+
*/
|
|
1474
|
+
if (vec[i] != 0) {
|
|
1475
|
+
offset = (uoffset_t)(vec[i] - base - (soffset_t)(i * field_size) -
|
|
1476
|
+
(soffset_t)field_size);
|
|
1477
|
+
write_uoffset(&vec[i], offset);
|
|
1478
|
+
if (types) {
|
|
1479
|
+
check(types[i] != 0,
|
|
1480
|
+
"union vector cannot have non-null element with type NONE");
|
|
1481
|
+
}
|
|
1482
|
+
} else {
|
|
1483
|
+
if (types) {
|
|
1484
|
+
check(types[i] == 0,
|
|
1485
|
+
"union vector cannot have null element without type NONE");
|
|
1486
|
+
} else {
|
|
1487
|
+
check(0, "offset vector cannot have null element");
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return emit_front(B, &iov);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
flatcc_builder_ref_t flatcc_builder_create_offset_vector_direct(
|
|
1495
|
+
flatcc_builder_t *B, flatcc_builder_ref_t *vec, size_t count) {
|
|
1496
|
+
return _create_offset_vector_direct(B, vec, count, 0);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
flatcc_builder_ref_t flatcc_builder_end_offset_vector(flatcc_builder_t *B) {
|
|
1500
|
+
flatcc_builder_ref_t vector_ref;
|
|
1501
|
+
|
|
1502
|
+
check(frame(type) == flatcc_builder_offset_vector,
|
|
1503
|
+
"expected offset vector frame");
|
|
1504
|
+
if (0 ==
|
|
1505
|
+
(vector_ref = flatcc_builder_create_offset_vector_direct(
|
|
1506
|
+
B, (flatcc_builder_ref_t *)B->ds, frame(container.vector.count)))) {
|
|
1507
|
+
return 0;
|
|
1508
|
+
}
|
|
1509
|
+
exit_frame(B);
|
|
1510
|
+
return vector_ref;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
flatcc_builder_ref_t flatcc_builder_end_offset_vector_for_unions(
|
|
1514
|
+
flatcc_builder_t *B, const utype_t *types) {
|
|
1515
|
+
flatcc_builder_ref_t vector_ref;
|
|
1516
|
+
|
|
1517
|
+
check(frame(type) == flatcc_builder_offset_vector,
|
|
1518
|
+
"expected offset vector frame");
|
|
1519
|
+
if (0 == (vector_ref = _create_offset_vector_direct(
|
|
1520
|
+
B, (flatcc_builder_ref_t *)B->ds, frame(container.vector.count),
|
|
1521
|
+
types))) {
|
|
1522
|
+
return 0;
|
|
1523
|
+
}
|
|
1524
|
+
exit_frame(B);
|
|
1525
|
+
return vector_ref;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
void *flatcc_builder_offset_vector_edit(flatcc_builder_t *B) { return B->ds; }
|
|
1529
|
+
|
|
1530
|
+
size_t flatcc_builder_offset_vector_count(flatcc_builder_t *B) {
|
|
1531
|
+
return frame(container.vector.count);
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
int flatcc_builder_table_add_union(flatcc_builder_t *B, int id,
|
|
1535
|
+
flatcc_builder_union_ref_t uref) {
|
|
1536
|
+
flatcc_builder_ref_t *pref;
|
|
1537
|
+
flatcc_builder_utype_t *putype;
|
|
1538
|
+
|
|
1539
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1540
|
+
check_error(uref.type != 0 || uref.value == 0, -1,
|
|
1541
|
+
"expected null value for type NONE");
|
|
1542
|
+
if (uref.value != 0) {
|
|
1543
|
+
pref = flatcc_builder_table_add_offset(B, id);
|
|
1544
|
+
check_error(pref != 0, -1, "unable to add union value");
|
|
1545
|
+
*pref = uref.value;
|
|
1546
|
+
}
|
|
1547
|
+
putype = flatcc_builder_table_add(B, id - 1, utype_size, utype_size);
|
|
1548
|
+
check_error(putype != 0, -1, "unable to add union type");
|
|
1549
|
+
write_utype(putype, uref.type);
|
|
1550
|
+
return 0;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
int flatcc_builder_table_add_union_vector(
|
|
1554
|
+
flatcc_builder_t *B, int id, flatcc_builder_union_vec_ref_t uvref) {
|
|
1555
|
+
flatcc_builder_ref_t *pref;
|
|
1556
|
+
|
|
1557
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1558
|
+
check_error((uvref.type == 0) == (uvref.value == 0), -1,
|
|
1559
|
+
"expected both type and value vector, or neither");
|
|
1560
|
+
if (uvref.type != 0) {
|
|
1561
|
+
pref = flatcc_builder_table_add_offset(B, id - 1);
|
|
1562
|
+
check_error(pref != 0, -1, "unable to add union member");
|
|
1563
|
+
*pref = uvref.type;
|
|
1564
|
+
|
|
1565
|
+
pref = flatcc_builder_table_add_offset(B, id);
|
|
1566
|
+
check_error(pref != 0, -1, "unable to add union member");
|
|
1567
|
+
*pref = uvref.value;
|
|
1568
|
+
}
|
|
1569
|
+
return 0;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
flatcc_builder_union_vec_ref_t flatcc_builder_create_union_vector(
|
|
1573
|
+
flatcc_builder_t *B, const flatcc_builder_union_ref_t *urefs,
|
|
1574
|
+
size_t count) {
|
|
1575
|
+
flatcc_builder_union_vec_ref_t uvref = {0, 0};
|
|
1576
|
+
flatcc_builder_utype_t *types;
|
|
1577
|
+
flatcc_builder_ref_t *refs;
|
|
1578
|
+
size_t i;
|
|
1579
|
+
|
|
1580
|
+
if (flatcc_builder_start_offset_vector(B)) {
|
|
1581
|
+
return uvref;
|
|
1582
|
+
}
|
|
1583
|
+
if (0 == flatcc_builder_extend_offset_vector(B, count)) {
|
|
1584
|
+
return uvref;
|
|
1585
|
+
}
|
|
1586
|
+
if (0 == (types = push_ds(B, (uoffset_t)(utype_size * count)))) {
|
|
1587
|
+
return uvref;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
/* Safe even if push_ds caused stack reallocation. */
|
|
1591
|
+
refs = flatcc_builder_offset_vector_edit(B);
|
|
1592
|
+
|
|
1593
|
+
for (i = 0; i < count; ++i) {
|
|
1594
|
+
types[i] = urefs[i].type;
|
|
1595
|
+
refs[i] = urefs[i].value;
|
|
1596
|
+
}
|
|
1597
|
+
uvref = flatcc_builder_create_union_vector_direct(B, types, refs, count);
|
|
1598
|
+
/* No need to clean up after out temporary types vector. */
|
|
1599
|
+
exit_frame(B);
|
|
1600
|
+
return uvref;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
flatcc_builder_union_vec_ref_t flatcc_builder_create_union_vector_direct(
|
|
1604
|
+
flatcc_builder_t *B, const flatcc_builder_utype_t *types,
|
|
1605
|
+
flatcc_builder_ref_t *data, size_t count) {
|
|
1606
|
+
flatcc_builder_union_vec_ref_t uvref = {0, 0};
|
|
1607
|
+
|
|
1608
|
+
if (0 ==
|
|
1609
|
+
(uvref.value = _create_offset_vector_direct(B, data, count, types))) {
|
|
1610
|
+
return uvref;
|
|
1611
|
+
}
|
|
1612
|
+
if (0 == (uvref.type = flatcc_builder_create_type_vector(B, types, count))) {
|
|
1613
|
+
return uvref;
|
|
1614
|
+
}
|
|
1615
|
+
return uvref;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
flatcc_builder_ref_t flatcc_builder_create_type_vector(
|
|
1619
|
+
flatcc_builder_t *B, const flatcc_builder_utype_t *types, size_t count) {
|
|
1620
|
+
return flatcc_builder_create_vector(B, types, count, utype_size, utype_size,
|
|
1621
|
+
max_utype_count);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
int flatcc_builder_start_union_vector(flatcc_builder_t *B) {
|
|
1625
|
+
if (enter_frame(B, field_size)) {
|
|
1626
|
+
return -1;
|
|
1627
|
+
}
|
|
1628
|
+
frame(container.vector.elem_size) = union_size;
|
|
1629
|
+
frame(container.vector.count) = 0;
|
|
1630
|
+
frame(type) = flatcc_builder_union_vector;
|
|
1631
|
+
refresh_ds(B, data_limit);
|
|
1632
|
+
return 0;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
flatcc_builder_union_vec_ref_t flatcc_builder_end_union_vector(
|
|
1636
|
+
flatcc_builder_t *B) {
|
|
1637
|
+
flatcc_builder_union_vec_ref_t uvref = {0, 0};
|
|
1638
|
+
flatcc_builder_utype_t *types;
|
|
1639
|
+
flatcc_builder_union_ref_t *urefs;
|
|
1640
|
+
flatcc_builder_ref_t *refs;
|
|
1641
|
+
size_t i, count;
|
|
1642
|
+
|
|
1643
|
+
check(frame(type) == flatcc_builder_union_vector,
|
|
1644
|
+
"expected union vector frame");
|
|
1645
|
+
|
|
1646
|
+
/*
|
|
1647
|
+
* We could split the union vector in-place, but then we would have
|
|
1648
|
+
* to deal with strict pointer aliasing rules which is not worthwhile
|
|
1649
|
+
* so we create a new offset and type vector on the stack.
|
|
1650
|
+
*
|
|
1651
|
+
* We assume the stack is sufficiently aligned as is.
|
|
1652
|
+
*/
|
|
1653
|
+
count = flatcc_builder_union_vector_count(B);
|
|
1654
|
+
if (0 ==
|
|
1655
|
+
(refs = push_ds(B, (uoffset_t)(count * (utype_size + field_size))))) {
|
|
1656
|
+
return uvref;
|
|
1657
|
+
}
|
|
1658
|
+
types = (flatcc_builder_utype_t *)(refs + count);
|
|
1659
|
+
|
|
1660
|
+
/* Safe even if push_ds caused stack reallocation. */
|
|
1661
|
+
urefs = flatcc_builder_union_vector_edit(B);
|
|
1662
|
+
|
|
1663
|
+
for (i = 0; i < count; ++i) {
|
|
1664
|
+
types[i] = urefs[i].type;
|
|
1665
|
+
refs[i] = urefs[i].value;
|
|
1666
|
+
}
|
|
1667
|
+
uvref = flatcc_builder_create_union_vector_direct(B, types, refs, count);
|
|
1668
|
+
/* No need to clean up after out temporary types vector. */
|
|
1669
|
+
exit_frame(B);
|
|
1670
|
+
return uvref;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
void *flatcc_builder_union_vector_edit(flatcc_builder_t *B) { return B->ds; }
|
|
1674
|
+
|
|
1675
|
+
size_t flatcc_builder_union_vector_count(flatcc_builder_t *B) {
|
|
1676
|
+
return frame(container.vector.count);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
flatcc_builder_union_ref_t *flatcc_builder_extend_union_vector(
|
|
1680
|
+
flatcc_builder_t *B, size_t count) {
|
|
1681
|
+
if (vector_count_add(B, (uoffset_t)count, max_union_count)) {
|
|
1682
|
+
return 0;
|
|
1683
|
+
}
|
|
1684
|
+
return push_ds(B, (uoffset_t)(union_size * count));
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
int flatcc_builder_truncate_union_vector(flatcc_builder_t *B, size_t count) {
|
|
1688
|
+
check(frame(type) == flatcc_builder_union_vector,
|
|
1689
|
+
"expected union vector frame");
|
|
1690
|
+
check_error(frame(container.vector.count) >= (uoffset_t)count, -1,
|
|
1691
|
+
"cannot truncate vector past empty");
|
|
1692
|
+
frame(container.vector.count) -= (uoffset_t)count;
|
|
1693
|
+
unpush_ds(B, frame(container.vector.elem_size) * (uoffset_t)count);
|
|
1694
|
+
return 0;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
flatcc_builder_union_ref_t *flatcc_builder_union_vector_push(
|
|
1698
|
+
flatcc_builder_t *B, flatcc_builder_union_ref_t uref) {
|
|
1699
|
+
flatcc_builder_union_ref_t *p;
|
|
1700
|
+
|
|
1701
|
+
check(frame(type) == flatcc_builder_union_vector,
|
|
1702
|
+
"expected union vector frame");
|
|
1703
|
+
if (frame(container.vector.count) == max_union_count) {
|
|
1704
|
+
return 0;
|
|
1705
|
+
}
|
|
1706
|
+
frame(container.vector.count) += 1;
|
|
1707
|
+
if (0 == (p = push_ds(B, union_size))) {
|
|
1708
|
+
return 0;
|
|
1709
|
+
}
|
|
1710
|
+
*p = uref;
|
|
1711
|
+
return p;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
flatcc_builder_union_ref_t *flatcc_builder_append_union_vector(
|
|
1715
|
+
flatcc_builder_t *B, const flatcc_builder_union_ref_t *urefs,
|
|
1716
|
+
size_t count) {
|
|
1717
|
+
check(frame(type) == flatcc_builder_union_vector,
|
|
1718
|
+
"expected union vector frame");
|
|
1719
|
+
if (vector_count_add(B, (uoffset_t)count, max_union_count)) {
|
|
1720
|
+
return 0;
|
|
1721
|
+
}
|
|
1722
|
+
return push_ds_copy(B, urefs, (uoffset_t)(union_size * count));
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
flatcc_builder_ref_t flatcc_builder_create_string(flatcc_builder_t *B,
|
|
1726
|
+
const char *s, size_t len) {
|
|
1727
|
+
uoffset_t s_pad;
|
|
1728
|
+
uoffset_t length_prefix;
|
|
1729
|
+
iov_state_t iov;
|
|
1730
|
+
|
|
1731
|
+
if (len > max_string_len) {
|
|
1732
|
+
return 0;
|
|
1733
|
+
}
|
|
1734
|
+
write_uoffset(&length_prefix, (uoffset_t)len);
|
|
1735
|
+
/* Add 1 for zero termination. */
|
|
1736
|
+
s_pad = front_pad(B, (uoffset_t)len + 1, field_size) + 1;
|
|
1737
|
+
init_iov();
|
|
1738
|
+
push_iov(&length_prefix, field_size);
|
|
1739
|
+
push_iov(s, len);
|
|
1740
|
+
push_iov(_pad, s_pad);
|
|
1741
|
+
return emit_front(B, &iov);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
flatcc_builder_ref_t flatcc_builder_create_string_str(flatcc_builder_t *B,
|
|
1745
|
+
const char *s) {
|
|
1746
|
+
return flatcc_builder_create_string(B, s, strlen(s));
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
flatcc_builder_ref_t flatcc_builder_create_string_strn(flatcc_builder_t *B,
|
|
1750
|
+
const char *s,
|
|
1751
|
+
size_t max_len) {
|
|
1752
|
+
return flatcc_builder_create_string(B, s, strnlen(s, max_len));
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
flatcc_builder_ref_t flatcc_builder_end_string(flatcc_builder_t *B) {
|
|
1756
|
+
flatcc_builder_ref_t string_ref;
|
|
1757
|
+
|
|
1758
|
+
check(frame(type) == flatcc_builder_string, "expected string frame");
|
|
1759
|
+
FLATCC_ASSERT(frame(container.vector.count) == B->ds_offset);
|
|
1760
|
+
if (0 == (string_ref = flatcc_builder_create_string(B, (const char *)B->ds,
|
|
1761
|
+
B->ds_offset))) {
|
|
1762
|
+
return 0;
|
|
1763
|
+
}
|
|
1764
|
+
exit_frame(B);
|
|
1765
|
+
return string_ref;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
char *flatcc_builder_string_edit(flatcc_builder_t *B) { return (char *)B->ds; }
|
|
1769
|
+
|
|
1770
|
+
size_t flatcc_builder_string_len(flatcc_builder_t *B) {
|
|
1771
|
+
return frame(container.vector.count);
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
void *flatcc_builder_table_add(flatcc_builder_t *B, int id, size_t size,
|
|
1775
|
+
uint16_t align) {
|
|
1776
|
+
/*
|
|
1777
|
+
* We align the offset relative to the first table field, excluding
|
|
1778
|
+
* the header holding the vtable reference. On the stack, `ds_first`
|
|
1779
|
+
* is aligned to 8 bytes thanks to the `enter_frame` logic, and this
|
|
1780
|
+
* provides a safe way to update the fields on the stack, but here
|
|
1781
|
+
* we are concerned with the target buffer alignment.
|
|
1782
|
+
*
|
|
1783
|
+
* We could also have aligned relative to the end of the table which
|
|
1784
|
+
* would allow us to emit each field immediately, but it would be a
|
|
1785
|
+
* confusing user experience wrt. field ordering, and it would add
|
|
1786
|
+
* more variability to vtable layouts, thus reducing reuse, and
|
|
1787
|
+
* frequent emissions to external emitter interface would be
|
|
1788
|
+
* sub-optimal. Also, with that appoach, the vtable offsets would
|
|
1789
|
+
* have to be adjusted at table end.
|
|
1790
|
+
*
|
|
1791
|
+
* As we have it, each emit occur at table end, vector end, string
|
|
1792
|
+
* end, or buffer end, which might be helpful to various backend
|
|
1793
|
+
* processors.
|
|
1794
|
+
*/
|
|
1795
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1796
|
+
check(id >= 0 && id <= (int)FLATBUFFERS_ID_MAX, "table id out of range");
|
|
1797
|
+
if (align > B->align) {
|
|
1798
|
+
B->align = align;
|
|
1799
|
+
}
|
|
1800
|
+
#if FLATCC_BUILDER_ALLOW_REPEAT_TABLE_ADD
|
|
1801
|
+
if (B->vs[id] != 0) {
|
|
1802
|
+
return B->ds + B->vs[id] - field_size;
|
|
1803
|
+
}
|
|
1804
|
+
#else
|
|
1805
|
+
if (B->vs[id] != 0) {
|
|
1806
|
+
check(0, "table field already set");
|
|
1807
|
+
return 0;
|
|
1808
|
+
}
|
|
1809
|
+
#endif
|
|
1810
|
+
FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)id, (uint32_t)size);
|
|
1811
|
+
return push_ds_field(B, (uoffset_t)size, align, (voffset_t)id);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
void *flatcc_builder_table_edit(flatcc_builder_t *B, size_t size) {
|
|
1815
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1816
|
+
|
|
1817
|
+
return B->ds + B->ds_offset - size;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
void *flatcc_builder_table_add_copy(flatcc_builder_t *B, int id,
|
|
1821
|
+
const void *data, size_t size,
|
|
1822
|
+
uint16_t align) {
|
|
1823
|
+
void *p;
|
|
1824
|
+
|
|
1825
|
+
if ((p = flatcc_builder_table_add(B, id, size, align))) {
|
|
1826
|
+
memcpy(p, data, size);
|
|
1827
|
+
}
|
|
1828
|
+
return p;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
flatcc_builder_ref_t *flatcc_builder_table_add_offset(flatcc_builder_t *B,
|
|
1832
|
+
int id) {
|
|
1833
|
+
check(frame(type) == flatcc_builder_table, "expected table frame");
|
|
1834
|
+
check(id >= 0 && id <= (int)FLATBUFFERS_ID_MAX, "table id out of range");
|
|
1835
|
+
#if FLATCC_BUILDER_ALLOW_REPEAT_TABLE_ADD
|
|
1836
|
+
if (B->vs[id] != 0) {
|
|
1837
|
+
return B->ds + B->vs[id] - field_size;
|
|
1838
|
+
}
|
|
1839
|
+
#else
|
|
1840
|
+
if (B->vs[id] != 0) {
|
|
1841
|
+
check(0, "table field already set");
|
|
1842
|
+
return 0;
|
|
1843
|
+
}
|
|
1844
|
+
#endif
|
|
1845
|
+
FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)id, (uint32_t)field_size);
|
|
1846
|
+
return push_ds_offset_field(B, (voffset_t)id);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
uint16_t flatcc_builder_push_buffer_alignment(flatcc_builder_t *B) {
|
|
1850
|
+
uint16_t old_min_align = B->min_align;
|
|
1851
|
+
|
|
1852
|
+
B->min_align = field_size;
|
|
1853
|
+
return old_min_align;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
void flatcc_builder_pop_buffer_alignment(flatcc_builder_t *B,
|
|
1857
|
+
uint16_t pushed_align) {
|
|
1858
|
+
set_min_align(B, pushed_align);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
uint16_t flatcc_builder_get_buffer_alignment(flatcc_builder_t *B) {
|
|
1862
|
+
return B->min_align;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
void flatcc_builder_set_vtable_clustering(flatcc_builder_t *B, int enable) {
|
|
1866
|
+
/* Inverted because we zero all memory in B on init. */
|
|
1867
|
+
B->disable_vt_clustering = !enable;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
void flatcc_builder_set_block_align(flatcc_builder_t *B, uint16_t align) {
|
|
1871
|
+
B->block_align = align;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
int flatcc_builder_get_level(flatcc_builder_t *B) { return B->level; }
|
|
1875
|
+
|
|
1876
|
+
void flatcc_builder_set_max_level(flatcc_builder_t *B, int max_level) {
|
|
1877
|
+
B->max_level = max_level;
|
|
1878
|
+
if (B->limit_level < B->max_level) {
|
|
1879
|
+
B->limit_level = B->max_level;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
size_t flatcc_builder_get_buffer_size(flatcc_builder_t *B) {
|
|
1884
|
+
return (size_t)(B->emit_end - B->emit_start);
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
flatcc_builder_ref_t flatcc_builder_get_buffer_start(flatcc_builder_t *B) {
|
|
1888
|
+
return B->emit_start;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
flatcc_builder_ref_t flatcc_builder_get_buffer_end(flatcc_builder_t *B) {
|
|
1892
|
+
return B->emit_end;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
void flatcc_builder_set_vtable_cache_limit(flatcc_builder_t *B, size_t size) {
|
|
1896
|
+
B->vb_flush_limit = size;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
void flatcc_builder_set_identifier(flatcc_builder_t *B,
|
|
1900
|
+
const char identifier[identifier_size]) {
|
|
1901
|
+
set_identifier(identifier);
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
enum flatcc_builder_type flatcc_builder_get_type(flatcc_builder_t *B) {
|
|
1905
|
+
return B->frame ? frame(type) : flatcc_builder_empty;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
enum flatcc_builder_type flatcc_builder_get_type_at(flatcc_builder_t *B,
|
|
1909
|
+
int level) {
|
|
1910
|
+
if (level < 1 || level > B->level) {
|
|
1911
|
+
return flatcc_builder_empty;
|
|
1912
|
+
}
|
|
1913
|
+
return B->frame[level - B->level].type;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
void *flatcc_builder_get_direct_buffer(flatcc_builder_t *B, size_t *size_out) {
|
|
1917
|
+
if (B->is_default_emitter) {
|
|
1918
|
+
return flatcc_emitter_get_direct_buffer(&B->default_emit_context, size_out);
|
|
1919
|
+
} else {
|
|
1920
|
+
if (size_out) {
|
|
1921
|
+
*size_out = 0;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
return 0;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
void *flatcc_builder_copy_buffer(flatcc_builder_t *B, void *buffer,
|
|
1928
|
+
size_t size) {
|
|
1929
|
+
/* User is allowed to call tentatively to see if there is support. */
|
|
1930
|
+
if (!B->is_default_emitter) {
|
|
1931
|
+
return 0;
|
|
1932
|
+
}
|
|
1933
|
+
buffer = flatcc_emitter_copy_buffer(&B->default_emit_context, buffer, size);
|
|
1934
|
+
check(buffer, "default emitter declined to copy buffer");
|
|
1935
|
+
return buffer;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
void *flatcc_builder_finalize_buffer(flatcc_builder_t *B, size_t *size_out) {
|
|
1939
|
+
void *buffer;
|
|
1940
|
+
size_t size;
|
|
1941
|
+
|
|
1942
|
+
size = flatcc_builder_get_buffer_size(B);
|
|
1943
|
+
|
|
1944
|
+
if (size_out) {
|
|
1945
|
+
*size_out = size;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
buffer = FLATCC_BUILDER_ALLOC(size);
|
|
1949
|
+
|
|
1950
|
+
if (!buffer) {
|
|
1951
|
+
check(0, "failed to allocated memory for finalized buffer");
|
|
1952
|
+
goto done;
|
|
1953
|
+
}
|
|
1954
|
+
if (!flatcc_builder_copy_buffer(B, buffer, size)) {
|
|
1955
|
+
check(0, "default emitter declined to copy buffer");
|
|
1956
|
+
FLATCC_BUILDER_FREE(buffer);
|
|
1957
|
+
buffer = 0;
|
|
1958
|
+
}
|
|
1959
|
+
done:
|
|
1960
|
+
if (!buffer && size_out) {
|
|
1961
|
+
*size_out = 0;
|
|
1962
|
+
}
|
|
1963
|
+
return buffer;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
void *flatcc_builder_finalize_aligned_buffer(flatcc_builder_t *B,
|
|
1967
|
+
size_t *size_out) {
|
|
1968
|
+
void *buffer;
|
|
1969
|
+
size_t align;
|
|
1970
|
+
size_t size;
|
|
1971
|
+
|
|
1972
|
+
size = flatcc_builder_get_buffer_size(B);
|
|
1973
|
+
|
|
1974
|
+
if (size_out) {
|
|
1975
|
+
*size_out = size;
|
|
1976
|
+
}
|
|
1977
|
+
align = flatcc_builder_get_buffer_alignment(B);
|
|
1978
|
+
|
|
1979
|
+
size = (size + align - 1) & ~(align - 1);
|
|
1980
|
+
buffer = FLATCC_BUILDER_ALIGNED_ALLOC(align, size);
|
|
1981
|
+
|
|
1982
|
+
if (!buffer) {
|
|
1983
|
+
goto done;
|
|
1984
|
+
}
|
|
1985
|
+
if (!flatcc_builder_copy_buffer(B, buffer, size)) {
|
|
1986
|
+
FLATCC_BUILDER_ALIGNED_FREE(buffer);
|
|
1987
|
+
buffer = 0;
|
|
1988
|
+
goto done;
|
|
1989
|
+
}
|
|
1990
|
+
done:
|
|
1991
|
+
if (!buffer && size_out) {
|
|
1992
|
+
*size_out = 0;
|
|
1993
|
+
}
|
|
1994
|
+
return buffer;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
void *flatcc_builder_aligned_alloc(size_t alignment, size_t size) {
|
|
1998
|
+
return FLATCC_BUILDER_ALIGNED_ALLOC(alignment, size);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
void flatcc_builder_aligned_free(void *p) { FLATCC_BUILDER_ALIGNED_FREE(p); }
|
|
2002
|
+
|
|
2003
|
+
void *flatcc_builder_alloc(size_t size) { return FLATCC_BUILDER_ALLOC(size); }
|
|
2004
|
+
|
|
2005
|
+
void flatcc_builder_free(void *p) { FLATCC_BUILDER_FREE(p); }
|
|
2006
|
+
|
|
2007
|
+
void *flatcc_builder_get_emit_context(flatcc_builder_t *B) {
|
|
2008
|
+
return B->emit_context;
|
|
2009
|
+
}
|
|
2010
|
+
#include <stdlib.h>
|
|
2011
|
+
|
|
2012
|
+
#include "flatcc/flatcc_emitter.h"
|
|
2013
|
+
#include "flatcc/flatcc_rtconfig.h"
|
|
2014
|
+
|
|
2015
|
+
static int advance_front(flatcc_emitter_t *E) {
|
|
2016
|
+
flatcc_emitter_page_t *p = 0;
|
|
2017
|
+
|
|
2018
|
+
if (E->front && E->front->prev != E->back) {
|
|
2019
|
+
E->front->prev->page_offset =
|
|
2020
|
+
E->front->page_offset - FLATCC_EMITTER_PAGE_SIZE;
|
|
2021
|
+
E->front = E->front->prev;
|
|
2022
|
+
goto done;
|
|
2023
|
+
}
|
|
2024
|
+
if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) {
|
|
2025
|
+
return -1;
|
|
2026
|
+
}
|
|
2027
|
+
E->capacity += FLATCC_EMITTER_PAGE_SIZE;
|
|
2028
|
+
if (E->front) {
|
|
2029
|
+
p->prev = E->back;
|
|
2030
|
+
p->next = E->front;
|
|
2031
|
+
E->front->prev = p;
|
|
2032
|
+
E->back->next = p;
|
|
2033
|
+
E->front = p;
|
|
2034
|
+
goto done;
|
|
2035
|
+
}
|
|
2036
|
+
/*
|
|
2037
|
+
* The first page is shared between front and back to avoid
|
|
2038
|
+
* double unecessary extra allocation.
|
|
2039
|
+
*/
|
|
2040
|
+
E->front = p;
|
|
2041
|
+
E->back = p;
|
|
2042
|
+
p->next = p;
|
|
2043
|
+
p->prev = p;
|
|
2044
|
+
E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2045
|
+
E->back_cursor = E->front_cursor;
|
|
2046
|
+
E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2047
|
+
E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
|
|
2048
|
+
p->page_offset = -(flatbuffers_soffset_t)E->front_left;
|
|
2049
|
+
return 0;
|
|
2050
|
+
done:
|
|
2051
|
+
E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE;
|
|
2052
|
+
E->front_left = FLATCC_EMITTER_PAGE_SIZE;
|
|
2053
|
+
E->front->page_offset =
|
|
2054
|
+
E->front->next->page_offset - FLATCC_EMITTER_PAGE_SIZE;
|
|
2055
|
+
return 0;
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
static int advance_back(flatcc_emitter_t *E) {
|
|
2059
|
+
flatcc_emitter_page_t *p = 0;
|
|
2060
|
+
|
|
2061
|
+
if (E->back && E->back->next != E->front) {
|
|
2062
|
+
E->back = E->back->next;
|
|
2063
|
+
goto done;
|
|
2064
|
+
}
|
|
2065
|
+
if (!(p = FLATCC_EMITTER_ALLOC(sizeof(flatcc_emitter_page_t)))) {
|
|
2066
|
+
return -1;
|
|
2067
|
+
}
|
|
2068
|
+
E->capacity += FLATCC_EMITTER_PAGE_SIZE;
|
|
2069
|
+
if (E->back) {
|
|
2070
|
+
p->prev = E->back;
|
|
2071
|
+
p->next = E->front;
|
|
2072
|
+
E->front->prev = p;
|
|
2073
|
+
E->back->next = p;
|
|
2074
|
+
E->back = p;
|
|
2075
|
+
goto done;
|
|
2076
|
+
}
|
|
2077
|
+
/*
|
|
2078
|
+
* The first page is shared between front and back to avoid
|
|
2079
|
+
* double unecessary extra allocation.
|
|
2080
|
+
*/
|
|
2081
|
+
E->front = p;
|
|
2082
|
+
E->back = p;
|
|
2083
|
+
p->next = p;
|
|
2084
|
+
p->prev = p;
|
|
2085
|
+
E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2086
|
+
E->back_cursor = E->front_cursor;
|
|
2087
|
+
E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2088
|
+
E->back_left = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
|
|
2089
|
+
p->page_offset = -(flatbuffers_soffset_t)E->front_left;
|
|
2090
|
+
return 0;
|
|
2091
|
+
done:
|
|
2092
|
+
E->back_cursor = E->back->page;
|
|
2093
|
+
E->back_left = FLATCC_EMITTER_PAGE_SIZE;
|
|
2094
|
+
E->back->page_offset = E->back->prev->page_offset + FLATCC_EMITTER_PAGE_SIZE;
|
|
2095
|
+
return 0;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
static int copy_front(flatcc_emitter_t *E, uint8_t *data, size_t size) {
|
|
2099
|
+
size_t k;
|
|
2100
|
+
|
|
2101
|
+
data += size;
|
|
2102
|
+
while (size) {
|
|
2103
|
+
k = size;
|
|
2104
|
+
if (k > E->front_left) {
|
|
2105
|
+
k = E->front_left;
|
|
2106
|
+
if (k == 0) {
|
|
2107
|
+
if (advance_front(E)) {
|
|
2108
|
+
return -1;
|
|
2109
|
+
}
|
|
2110
|
+
continue;
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
E->front_cursor -= k;
|
|
2114
|
+
E->front_left -= k;
|
|
2115
|
+
data -= k;
|
|
2116
|
+
size -= k;
|
|
2117
|
+
memcpy(E->front_cursor, data, k);
|
|
2118
|
+
};
|
|
2119
|
+
return 0;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
static int copy_back(flatcc_emitter_t *E, uint8_t *data, size_t size) {
|
|
2123
|
+
size_t k;
|
|
2124
|
+
|
|
2125
|
+
while (size) {
|
|
2126
|
+
k = size;
|
|
2127
|
+
if (k > E->back_left) {
|
|
2128
|
+
k = E->back_left;
|
|
2129
|
+
if (k == 0) {
|
|
2130
|
+
if (advance_back(E)) {
|
|
2131
|
+
return -1;
|
|
2132
|
+
}
|
|
2133
|
+
continue;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
memcpy(E->back_cursor, data, k);
|
|
2137
|
+
size -= k;
|
|
2138
|
+
data += k;
|
|
2139
|
+
E->back_cursor += k;
|
|
2140
|
+
E->back_left -= k;
|
|
2141
|
+
}
|
|
2142
|
+
return 0;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
int flatcc_emitter_recycle_page(flatcc_emitter_t *E, flatcc_emitter_page_t *p) {
|
|
2146
|
+
if (p == E->front || p == E->back) {
|
|
2147
|
+
return -1;
|
|
2148
|
+
}
|
|
2149
|
+
p->next->prev = p->prev;
|
|
2150
|
+
p->prev->next = p->next;
|
|
2151
|
+
p->prev = E->front->prev;
|
|
2152
|
+
p->next = E->front;
|
|
2153
|
+
p->prev->next = p;
|
|
2154
|
+
p->next->prev = p;
|
|
2155
|
+
return 0;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
void flatcc_emitter_reset(flatcc_emitter_t *E) {
|
|
2159
|
+
flatcc_emitter_page_t *p = E->front;
|
|
2160
|
+
|
|
2161
|
+
if (!E->front) {
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
E->back = E->front;
|
|
2165
|
+
E->front_cursor = E->front->page + FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2166
|
+
E->back_cursor = E->front_cursor;
|
|
2167
|
+
E->front_left = FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2168
|
+
E->back_left = FLATCC_EMITTER_PAGE_SIZE - FLATCC_EMITTER_PAGE_SIZE / 2;
|
|
2169
|
+
E->front->page_offset = -(flatbuffers_soffset_t)E->front_left;
|
|
2170
|
+
/* Heuristic to reduce peak allocation over time. */
|
|
2171
|
+
if (E->used_average == 0) {
|
|
2172
|
+
E->used_average = E->used;
|
|
2173
|
+
}
|
|
2174
|
+
E->used_average = E->used_average * 3 / 4 + E->used / 4;
|
|
2175
|
+
E->used = 0;
|
|
2176
|
+
while (E->used_average * 2 < E->capacity && E->back->next != E->front) {
|
|
2177
|
+
/* We deallocate the page after back since it is less likely to be hot in
|
|
2178
|
+
* cache. */
|
|
2179
|
+
p = E->back->next;
|
|
2180
|
+
E->back->next = p->next;
|
|
2181
|
+
p->next->prev = E->back;
|
|
2182
|
+
FLATCC_EMITTER_FREE(p);
|
|
2183
|
+
E->capacity -= FLATCC_EMITTER_PAGE_SIZE;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
void flatcc_emitter_clear(flatcc_emitter_t *E) {
|
|
2188
|
+
flatcc_emitter_page_t *p = E->front;
|
|
2189
|
+
|
|
2190
|
+
if (!p) {
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
p->prev->next = 0;
|
|
2194
|
+
while (p->next) {
|
|
2195
|
+
p = p->next;
|
|
2196
|
+
FLATCC_EMITTER_FREE(p->prev);
|
|
2197
|
+
}
|
|
2198
|
+
FLATCC_EMITTER_FREE(p);
|
|
2199
|
+
memset(E, 0, sizeof(*E));
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
int flatcc_emitter(void *emit_context, const flatcc_iovec_t *iov, int iov_count,
|
|
2203
|
+
flatbuffers_soffset_t offset, size_t len) {
|
|
2204
|
+
flatcc_emitter_t *E = emit_context;
|
|
2205
|
+
uint8_t *p;
|
|
2206
|
+
|
|
2207
|
+
E->used += len;
|
|
2208
|
+
if (offset < 0) {
|
|
2209
|
+
if (len <= E->front_left) {
|
|
2210
|
+
E->front_cursor -= len;
|
|
2211
|
+
E->front_left -= len;
|
|
2212
|
+
p = E->front_cursor;
|
|
2213
|
+
goto copy;
|
|
2214
|
+
}
|
|
2215
|
+
iov += iov_count;
|
|
2216
|
+
while (iov_count--) {
|
|
2217
|
+
--iov;
|
|
2218
|
+
if (copy_front(E, iov->iov_base, iov->iov_len)) {
|
|
2219
|
+
return -1;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
} else {
|
|
2223
|
+
if (len <= E->back_left) {
|
|
2224
|
+
p = E->back_cursor;
|
|
2225
|
+
E->back_cursor += len;
|
|
2226
|
+
E->back_left -= len;
|
|
2227
|
+
goto copy;
|
|
2228
|
+
}
|
|
2229
|
+
while (iov_count--) {
|
|
2230
|
+
if (copy_back(E, iov->iov_base, iov->iov_len)) {
|
|
2231
|
+
return -1;
|
|
2232
|
+
}
|
|
2233
|
+
++iov;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
return 0;
|
|
2237
|
+
copy:
|
|
2238
|
+
while (iov_count--) {
|
|
2239
|
+
memcpy(p, iov->iov_base, iov->iov_len);
|
|
2240
|
+
p += iov->iov_len;
|
|
2241
|
+
++iov;
|
|
2242
|
+
}
|
|
2243
|
+
return 0;
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
void *flatcc_emitter_copy_buffer(flatcc_emitter_t *E, void *buf, size_t size) {
|
|
2247
|
+
flatcc_emitter_page_t *p;
|
|
2248
|
+
size_t len;
|
|
2249
|
+
|
|
2250
|
+
if (size < E->used) {
|
|
2251
|
+
return 0;
|
|
2252
|
+
}
|
|
2253
|
+
if (!E->front) {
|
|
2254
|
+
return 0;
|
|
2255
|
+
}
|
|
2256
|
+
if (E->front == E->back) {
|
|
2257
|
+
memcpy(buf, E->front_cursor, E->used);
|
|
2258
|
+
return buf;
|
|
2259
|
+
}
|
|
2260
|
+
len = FLATCC_EMITTER_PAGE_SIZE - E->front_left;
|
|
2261
|
+
memcpy(buf, E->front_cursor, len);
|
|
2262
|
+
buf = (uint8_t *)buf + len;
|
|
2263
|
+
p = E->front->next;
|
|
2264
|
+
while (p != E->back) {
|
|
2265
|
+
memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE);
|
|
2266
|
+
buf = (uint8_t *)buf + FLATCC_EMITTER_PAGE_SIZE;
|
|
2267
|
+
p = p->next;
|
|
2268
|
+
}
|
|
2269
|
+
memcpy(buf, p->page, FLATCC_EMITTER_PAGE_SIZE - E->back_left);
|
|
2270
|
+
return buf;
|
|
2271
|
+
}
|
|
2272
|
+
/*
|
|
2273
|
+
* Runtime support for verifying flatbuffers.
|
|
2274
|
+
*
|
|
2275
|
+
* Depends mutually on generated verifier functions for table types that
|
|
2276
|
+
* call into this library.
|
|
2277
|
+
*/
|
|
2278
|
+
#include <string.h>
|
|
2279
|
+
|
|
2280
|
+
#include "flatcc/flatcc_flatbuffers.h"
|
|
2281
|
+
#include "flatcc/flatcc_identifier.h"
|
|
2282
|
+
#include "flatcc/flatcc_rtconfig.h"
|
|
2283
|
+
#include "flatcc/flatcc_verifier.h"
|
|
2284
|
+
|
|
2285
|
+
/* Customization for testing. */
|
|
2286
|
+
#if FLATCC_DEBUG_VERIFY
|
|
2287
|
+
#define FLATCC_VERIFIER_ASSERT_ON_ERROR 1
|
|
2288
|
+
#include <stdio.h>
|
|
2289
|
+
#define FLATCC_VERIFIER_ASSERT(cond, reason) \
|
|
2290
|
+
if (!(cond)) { \
|
|
2291
|
+
fprintf(stderr, "verifier assert: %s\n", \
|
|
2292
|
+
flatcc_verify_error_string(reason)); \
|
|
2293
|
+
FLATCC_ASSERT(0); \
|
|
2294
|
+
return reason; \
|
|
2295
|
+
}
|
|
2296
|
+
#endif
|
|
2297
|
+
|
|
2298
|
+
#if FLATCC_TRACE_VERIFY
|
|
2299
|
+
#include <stdio.h>
|
|
2300
|
+
#define trace_verify(s, p) \
|
|
2301
|
+
fprintf(stderr, "trace verify: %s: 0x%02x\n", (s), (unsigned)(size_t)(p));
|
|
2302
|
+
#else
|
|
2303
|
+
#define trace_verify(s, p) ((void)0)
|
|
2304
|
+
#endif
|
|
2305
|
+
|
|
2306
|
+
/* The runtime library does not use the global config file. */
|
|
2307
|
+
|
|
2308
|
+
/* This is a guideline, not an exact measure. */
|
|
2309
|
+
#ifndef FLATCC_VERIFIER_MAX_LEVELS
|
|
2310
|
+
#define FLATCC_VERIFIER_MAX_LEVELS 100
|
|
2311
|
+
#endif
|
|
2312
|
+
|
|
2313
|
+
#ifndef FLATCC_VERIFIER_ASSERT_ON_ERROR
|
|
2314
|
+
#define FLATCC_VERIFIER_ASSERT_ON_ERROR 0
|
|
2315
|
+
#endif
|
|
2316
|
+
|
|
2317
|
+
/*
|
|
2318
|
+
* Generally a check should tell if a buffer is valid or not such
|
|
2319
|
+
* that runtime can take appropriate actions rather than crash,
|
|
2320
|
+
* also in debug, but assertions are helpful in debugging a problem.
|
|
2321
|
+
*
|
|
2322
|
+
* This must be compiled into the debug runtime library to take effect.
|
|
2323
|
+
*/
|
|
2324
|
+
#ifndef FLATCC_VERIFIER_ASSERT_ON_ERROR
|
|
2325
|
+
#define FLATCC_VERIFIER_ASSERT_ON_ERROR 1
|
|
2326
|
+
#endif
|
|
2327
|
+
|
|
2328
|
+
/* May be redefined for logging purposes. */
|
|
2329
|
+
#ifndef FLATCC_VERIFIER_ASSERT
|
|
2330
|
+
#define FLATCC_VERIFIER_ASSERT(cond, reason) FLATCC_ASSERT(cond)
|
|
2331
|
+
#endif
|
|
2332
|
+
|
|
2333
|
+
#if FLATCC_VERIFIER_ASSERT_ON_ERROR
|
|
2334
|
+
#define flatcc_verify(cond, reason) \
|
|
2335
|
+
if (!(cond)) { \
|
|
2336
|
+
FLATCC_VERIFIER_ASSERT(cond, reason); \
|
|
2337
|
+
return reason; \
|
|
2338
|
+
}
|
|
2339
|
+
#else
|
|
2340
|
+
#define flatcc_verify(cond, reason) \
|
|
2341
|
+
if (!(cond)) { \
|
|
2342
|
+
return reason; \
|
|
2343
|
+
}
|
|
2344
|
+
#endif
|
|
2345
|
+
|
|
2346
|
+
#define uoffset_t flatbuffers_uoffset_t
|
|
2347
|
+
#define soffset_t flatbuffers_soffset_t
|
|
2348
|
+
#define voffset_t flatbuffers_voffset_t
|
|
2349
|
+
#define utype_t flatbuffers_utype_t
|
|
2350
|
+
#define thash_t flatbuffers_thash_t
|
|
2351
|
+
|
|
2352
|
+
#define uoffset_size sizeof(uoffset_t)
|
|
2353
|
+
#define soffset_size sizeof(soffset_t)
|
|
2354
|
+
#define voffset_size sizeof(voffset_t)
|
|
2355
|
+
#define utype_size sizeof(utype_t)
|
|
2356
|
+
#define thash_size sizeof(thash_t)
|
|
2357
|
+
#define offset_size uoffset_size
|
|
2358
|
+
|
|
2359
|
+
const char *flatcc_verify_error_string(int err) {
|
|
2360
|
+
switch (err) {
|
|
2361
|
+
#define XX(no, str) \
|
|
2362
|
+
case flatcc_verify_error_##no: \
|
|
2363
|
+
return str;
|
|
2364
|
+
FLATCC_VERIFY_ERROR_MAP(XX)
|
|
2365
|
+
#undef XX
|
|
2366
|
+
default:
|
|
2367
|
+
return "unknown";
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
/* `cond` may have side effects. */
|
|
2372
|
+
#define verify(cond, reason) \
|
|
2373
|
+
do { \
|
|
2374
|
+
int c = (cond); \
|
|
2375
|
+
flatcc_verify(c, reason); \
|
|
2376
|
+
} while (0)
|
|
2377
|
+
|
|
2378
|
+
/*
|
|
2379
|
+
* Identify checks related to runtime conditions (buffer size and
|
|
2380
|
+
* alignment) as seperate from those related to buffer content.
|
|
2381
|
+
*/
|
|
2382
|
+
#define verify_runtime(cond, reason) verify(cond, reason)
|
|
2383
|
+
|
|
2384
|
+
#define check_result(x) \
|
|
2385
|
+
if (x) { \
|
|
2386
|
+
return (x); \
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
#define check_field(td, id, required, base) \
|
|
2390
|
+
do { \
|
|
2391
|
+
int ret = get_offset_field(td, id, required, &base); \
|
|
2392
|
+
if (ret || !base) { \
|
|
2393
|
+
return ret; \
|
|
2394
|
+
} \
|
|
2395
|
+
} while (0)
|
|
2396
|
+
|
|
2397
|
+
static inline uoffset_t read_uoffset(const void *p, uoffset_t base) {
|
|
2398
|
+
return __flatbuffers_uoffset_read_from_pe((uint8_t *)p + base);
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
static inline thash_t read_thash_identifier(const char *identifier) {
|
|
2402
|
+
return flatbuffers_type_hash_from_string(identifier);
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
static inline thash_t read_thash(const void *p, uoffset_t base) {
|
|
2406
|
+
return __flatbuffers_thash_read_from_pe((uint8_t *)p + base);
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
static inline voffset_t read_voffset(const void *p, uoffset_t base) {
|
|
2410
|
+
return __flatbuffers_voffset_read_from_pe((uint8_t *)p + base);
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
static inline int check_header(uoffset_t end, uoffset_t base,
|
|
2414
|
+
uoffset_t offset) {
|
|
2415
|
+
uoffset_t k = base + offset;
|
|
2416
|
+
|
|
2417
|
+
if (uoffset_size <= voffset_size && k + offset_size < k) {
|
|
2418
|
+
return 0;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/* The `k > base` rather than `k >= base` is to avoid null offsets. */
|
|
2422
|
+
return k > base && k + offset_size <= end && !(k & (offset_size - 1));
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
static inline int check_aligned_header(uoffset_t end, uoffset_t base,
|
|
2426
|
+
uoffset_t offset, uint16_t align) {
|
|
2427
|
+
uoffset_t k = base + offset;
|
|
2428
|
+
|
|
2429
|
+
if (uoffset_size <= voffset_size && k + offset_size < k) {
|
|
2430
|
+
return 0;
|
|
2431
|
+
}
|
|
2432
|
+
/* Alignment refers to element 0 and header must also be aligned. */
|
|
2433
|
+
align = align < uoffset_size ? uoffset_size : align;
|
|
2434
|
+
|
|
2435
|
+
/* Note to self: the builder can also use the mask OR trick to propagate
|
|
2436
|
+
* `min_align`. */
|
|
2437
|
+
return k > base && k + offset_size <= end &&
|
|
2438
|
+
!((k + offset_size) & ((offset_size - 1) | (align - 1u)));
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
static inline int verify_struct(uoffset_t end, uoffset_t base, uoffset_t offset,
|
|
2442
|
+
uoffset_t size, uint16_t align) {
|
|
2443
|
+
/* Structs can have zero size so `end` is a valid value. */
|
|
2444
|
+
if (offset == 0 || base + offset > end) {
|
|
2445
|
+
return flatcc_verify_error_offset_out_of_range;
|
|
2446
|
+
}
|
|
2447
|
+
base += offset;
|
|
2448
|
+
verify(base + size >= base, flatcc_verify_error_struct_size_overflow);
|
|
2449
|
+
verify(base + size <= end, flatcc_verify_error_struct_out_of_range);
|
|
2450
|
+
verify(!(base & (align - 1u)), flatcc_verify_error_struct_unaligned);
|
|
2451
|
+
return flatcc_verify_ok;
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
static inline voffset_t read_vt_entry(flatcc_table_verifier_descriptor_t *td,
|
|
2455
|
+
voffset_t id) {
|
|
2456
|
+
voffset_t vo = (id + 2u) * sizeof(voffset_t);
|
|
2457
|
+
|
|
2458
|
+
/* Assumes tsize has been verified for alignment. */
|
|
2459
|
+
if (vo >= td->vsize) {
|
|
2460
|
+
return 0;
|
|
2461
|
+
}
|
|
2462
|
+
return read_voffset(td->vtable, vo);
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
static inline const void *get_field_ptr(flatcc_table_verifier_descriptor_t *td,
|
|
2466
|
+
voffset_t id) {
|
|
2467
|
+
voffset_t vte = read_vt_entry(td, id);
|
|
2468
|
+
return vte ? (const uint8_t *)td->buf + td->table + vte : 0;
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
static int verify_field(flatcc_table_verifier_descriptor_t *td, voffset_t id,
|
|
2472
|
+
int required, uoffset_t size, uint16_t align) {
|
|
2473
|
+
uoffset_t k, k2;
|
|
2474
|
+
voffset_t vte;
|
|
2475
|
+
uoffset_t base = (uoffset_t)(size_t)td->buf;
|
|
2476
|
+
|
|
2477
|
+
/*
|
|
2478
|
+
* Otherwise range check assumptions break, and normal access code likely
|
|
2479
|
+
* also. We don't require voffset_size < uoffset_size, but some checks are
|
|
2480
|
+
* faster if true.
|
|
2481
|
+
*/
|
|
2482
|
+
FLATCC_ASSERT(uoffset_size >= voffset_size);
|
|
2483
|
+
FLATCC_ASSERT(soffset_size == uoffset_size);
|
|
2484
|
+
|
|
2485
|
+
vte = read_vt_entry(td, id);
|
|
2486
|
+
if (!vte) {
|
|
2487
|
+
verify(!required, flatcc_verify_error_required_field_missing);
|
|
2488
|
+
return flatcc_verify_ok;
|
|
2489
|
+
}
|
|
2490
|
+
trace_verify("table buffer", td->buf);
|
|
2491
|
+
trace_verify("table", td->table);
|
|
2492
|
+
trace_verify("id", id);
|
|
2493
|
+
trace_verify("vte", vte);
|
|
2494
|
+
|
|
2495
|
+
/*
|
|
2496
|
+
* Note that we don't add td.table to k and we test against table
|
|
2497
|
+
* size not table end or buffer end. Otherwise it would not be safe
|
|
2498
|
+
* to optimized out the k <= k2 check for normal uoffset and voffset
|
|
2499
|
+
* configurations.
|
|
2500
|
+
*/
|
|
2501
|
+
k = vte;
|
|
2502
|
+
k2 = k + size;
|
|
2503
|
+
verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range);
|
|
2504
|
+
/* This normally optimizes to nop. */
|
|
2505
|
+
verify(uoffset_size > voffset_size || k <= k2,
|
|
2506
|
+
flatcc_verify_error_table_field_size_overflow);
|
|
2507
|
+
trace_verify("table + vte", vte + td->table);
|
|
2508
|
+
k += td->table + base;
|
|
2509
|
+
trace_verify("entry: buf + table + vte", k);
|
|
2510
|
+
trace_verify("align", align);
|
|
2511
|
+
trace_verify("align masked entry", k & (align - 1u));
|
|
2512
|
+
verify(!(k & (align - 1u)), flatcc_verify_error_table_field_not_aligned);
|
|
2513
|
+
/* We assume the table size has already been verified. */
|
|
2514
|
+
return flatcc_verify_ok;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
static int get_offset_field(flatcc_table_verifier_descriptor_t *td,
|
|
2518
|
+
voffset_t id, int required, uoffset_t *out) {
|
|
2519
|
+
uoffset_t k, k2;
|
|
2520
|
+
voffset_t vte;
|
|
2521
|
+
|
|
2522
|
+
vte = read_vt_entry(td, id);
|
|
2523
|
+
if (!vte) {
|
|
2524
|
+
*out = 0;
|
|
2525
|
+
if (required) {
|
|
2526
|
+
return flatcc_verify_error_required_field_missing;
|
|
2527
|
+
}
|
|
2528
|
+
/* Missing, but not invalid. */
|
|
2529
|
+
return flatcc_verify_ok;
|
|
2530
|
+
}
|
|
2531
|
+
/*
|
|
2532
|
+
* Note that we don't add td.table to k and we test against table
|
|
2533
|
+
* size not table end or buffer end. Otherwise it would not be safe
|
|
2534
|
+
* to optimized out the k <= k2 check for normal uoffset and voffset
|
|
2535
|
+
* configurations.
|
|
2536
|
+
*/
|
|
2537
|
+
k = vte;
|
|
2538
|
+
k2 = k + offset_size;
|
|
2539
|
+
verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range);
|
|
2540
|
+
/* This normally optimizes to nop. */
|
|
2541
|
+
verify(uoffset_size > voffset_size || k <= k2,
|
|
2542
|
+
flatcc_verify_error_table_field_size_overflow);
|
|
2543
|
+
k += td->table;
|
|
2544
|
+
verify(!(k & (offset_size - 1u)),
|
|
2545
|
+
flatcc_verify_error_table_field_not_aligned);
|
|
2546
|
+
/* We assume the table size has already been verified. */
|
|
2547
|
+
*out = k;
|
|
2548
|
+
return flatcc_verify_ok;
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
static inline int verify_string(const void *buf, uoffset_t end, uoffset_t base,
|
|
2552
|
+
uoffset_t offset) {
|
|
2553
|
+
uoffset_t n;
|
|
2554
|
+
|
|
2555
|
+
verify(check_header(end, base, offset),
|
|
2556
|
+
flatcc_verify_error_string_header_out_of_range_or_unaligned);
|
|
2557
|
+
base += offset;
|
|
2558
|
+
n = read_uoffset(buf, base);
|
|
2559
|
+
base += offset_size;
|
|
2560
|
+
verify(end - base > n, flatcc_verify_error_string_out_of_range);
|
|
2561
|
+
verify(((uint8_t *)buf + base)[n] == 0,
|
|
2562
|
+
flatcc_verify_error_string_not_zero_terminated);
|
|
2563
|
+
return flatcc_verify_ok;
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
/*
|
|
2567
|
+
* Keep interface somwewhat similar ot flatcc_builder_start_vector.
|
|
2568
|
+
* `max_count` is a precomputed division to manage overflow check on vector
|
|
2569
|
+
* length.
|
|
2570
|
+
*/
|
|
2571
|
+
static inline int verify_vector(const void *buf, uoffset_t end, uoffset_t base,
|
|
2572
|
+
uoffset_t offset, uoffset_t elem_size,
|
|
2573
|
+
uint16_t align, uoffset_t max_count) {
|
|
2574
|
+
uoffset_t n;
|
|
2575
|
+
|
|
2576
|
+
verify(check_aligned_header(end, base, offset, align),
|
|
2577
|
+
flatcc_verify_error_vector_header_out_of_range_or_unaligned);
|
|
2578
|
+
base += offset;
|
|
2579
|
+
n = read_uoffset(buf, base);
|
|
2580
|
+
base += offset_size;
|
|
2581
|
+
/* `n * elem_size` can overflow uncontrollably otherwise. */
|
|
2582
|
+
verify(n <= max_count,
|
|
2583
|
+
flatcc_verify_error_vector_count_exceeds_representable_vector_size);
|
|
2584
|
+
verify(end - base >= n * elem_size, flatcc_verify_error_vector_out_of_range);
|
|
2585
|
+
return flatcc_verify_ok;
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
static inline int verify_string_vector(const void *buf, uoffset_t end,
|
|
2589
|
+
uoffset_t base, uoffset_t offset) {
|
|
2590
|
+
uoffset_t i, n;
|
|
2591
|
+
|
|
2592
|
+
check_result(verify_vector(buf, end, base, offset, offset_size, offset_size,
|
|
2593
|
+
FLATBUFFERS_COUNT_MAX(offset_size)));
|
|
2594
|
+
base += offset;
|
|
2595
|
+
n = read_uoffset(buf, base);
|
|
2596
|
+
base += offset_size;
|
|
2597
|
+
for (i = 0; i < n; ++i, base += offset_size) {
|
|
2598
|
+
check_result(verify_string(buf, end, base, read_uoffset(buf, base)));
|
|
2599
|
+
}
|
|
2600
|
+
return flatcc_verify_ok;
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
static inline int verify_table(const void *buf, uoffset_t end, uoffset_t base,
|
|
2604
|
+
uoffset_t offset, int ttl,
|
|
2605
|
+
flatcc_table_verifier_f tvf) {
|
|
2606
|
+
uoffset_t vbase, vend;
|
|
2607
|
+
flatcc_table_verifier_descriptor_t td;
|
|
2608
|
+
|
|
2609
|
+
verify((td.ttl = ttl - 1), flatcc_verify_error_max_nesting_level_reached);
|
|
2610
|
+
verify(check_header(end, base, offset),
|
|
2611
|
+
flatcc_verify_error_table_header_out_of_range_or_unaligned);
|
|
2612
|
+
td.table = base + offset;
|
|
2613
|
+
/* Read vtable offset - it is signed, but we want it unsigned, assuming 2's
|
|
2614
|
+
* complement works. */
|
|
2615
|
+
vbase = td.table - read_uoffset(buf, td.table);
|
|
2616
|
+
verify((soffset_t)vbase >= 0 && !(vbase & (voffset_size - 1)),
|
|
2617
|
+
flatcc_verify_error_vtable_offset_out_of_range_or_unaligned);
|
|
2618
|
+
verify(vbase + voffset_size <= end,
|
|
2619
|
+
flatcc_verify_error_vtable_header_out_of_range);
|
|
2620
|
+
/* Read vtable size. */
|
|
2621
|
+
td.vsize = read_voffset(buf, vbase);
|
|
2622
|
+
vend = vbase + td.vsize;
|
|
2623
|
+
verify(vend <= end && !(td.vsize & (voffset_size - 1)),
|
|
2624
|
+
flatcc_verify_error_vtable_size_out_of_range_or_unaligned);
|
|
2625
|
+
/* Optimizes away overflow check if uoffset_t is large enough. */
|
|
2626
|
+
verify(uoffset_size > voffset_size || vend >= vbase,
|
|
2627
|
+
flatcc_verify_error_vtable_size_overflow);
|
|
2628
|
+
|
|
2629
|
+
verify(td.vsize >= 2 * voffset_size,
|
|
2630
|
+
flatcc_verify_error_vtable_header_too_small);
|
|
2631
|
+
/* Read table size. */
|
|
2632
|
+
td.tsize = read_voffset(buf, vbase + voffset_size);
|
|
2633
|
+
verify(end - td.table >= td.tsize,
|
|
2634
|
+
flatcc_verify_error_table_size_out_of_range);
|
|
2635
|
+
td.vtable = (uint8_t *)buf + vbase;
|
|
2636
|
+
td.buf = buf;
|
|
2637
|
+
td.end = end;
|
|
2638
|
+
return tvf(&td);
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
static inline int verify_table_vector(const void *buf, uoffset_t end,
|
|
2642
|
+
uoffset_t base, uoffset_t offset, int ttl,
|
|
2643
|
+
flatcc_table_verifier_f tvf) {
|
|
2644
|
+
uoffset_t i, n;
|
|
2645
|
+
|
|
2646
|
+
verify(ttl-- > 0, flatcc_verify_error_max_nesting_level_reached);
|
|
2647
|
+
check_result(verify_vector(buf, end, base, offset, offset_size, offset_size,
|
|
2648
|
+
FLATBUFFERS_COUNT_MAX(offset_size)));
|
|
2649
|
+
base += offset;
|
|
2650
|
+
n = read_uoffset(buf, base);
|
|
2651
|
+
base += offset_size;
|
|
2652
|
+
for (i = 0; i < n; ++i, base += offset_size) {
|
|
2653
|
+
check_result(
|
|
2654
|
+
verify_table(buf, end, base, read_uoffset(buf, base), ttl, tvf));
|
|
2655
|
+
}
|
|
2656
|
+
return flatcc_verify_ok;
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
static inline int verify_union_vector(const void *buf, uoffset_t end,
|
|
2660
|
+
uoffset_t base, uoffset_t offset,
|
|
2661
|
+
uoffset_t count, const utype_t *types,
|
|
2662
|
+
int ttl, flatcc_union_verifier_f uvf) {
|
|
2663
|
+
uoffset_t i, n, elem;
|
|
2664
|
+
flatcc_union_verifier_descriptor_t ud;
|
|
2665
|
+
|
|
2666
|
+
verify(ttl-- > 0, flatcc_verify_error_max_nesting_level_reached);
|
|
2667
|
+
check_result(verify_vector(buf, end, base, offset, offset_size, offset_size,
|
|
2668
|
+
FLATBUFFERS_COUNT_MAX(offset_size)));
|
|
2669
|
+
base += offset;
|
|
2670
|
+
n = read_uoffset(buf, base);
|
|
2671
|
+
verify(n == count, flatcc_verify_error_union_vector_length_mismatch);
|
|
2672
|
+
base += offset_size;
|
|
2673
|
+
|
|
2674
|
+
ud.buf = buf;
|
|
2675
|
+
ud.end = end;
|
|
2676
|
+
ud.ttl = ttl;
|
|
2677
|
+
|
|
2678
|
+
for (i = 0; i < n; ++i, base += offset_size) {
|
|
2679
|
+
/* Table vectors can never be null, but unions can when the type is NONE. */
|
|
2680
|
+
elem = read_uoffset(buf, base);
|
|
2681
|
+
if (elem == 0) {
|
|
2682
|
+
verify(types[i] == 0,
|
|
2683
|
+
flatcc_verify_error_union_element_absent_without_type_NONE);
|
|
2684
|
+
} else {
|
|
2685
|
+
verify(types[i] != 0,
|
|
2686
|
+
flatcc_verify_error_union_element_present_with_type_NONE);
|
|
2687
|
+
ud.type = types[i];
|
|
2688
|
+
ud.base = base;
|
|
2689
|
+
ud.offset = elem;
|
|
2690
|
+
check_result(uvf(&ud));
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
return flatcc_verify_ok;
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
int flatcc_verify_field(flatcc_table_verifier_descriptor_t *td, voffset_t id,
|
|
2697
|
+
size_t size, uint16_t align) {
|
|
2698
|
+
check_result(verify_field(td, id, 0, (uoffset_t)size, align));
|
|
2699
|
+
return flatcc_verify_ok;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
int flatcc_verify_string_field(flatcc_table_verifier_descriptor_t *td,
|
|
2703
|
+
voffset_t id, int required) {
|
|
2704
|
+
uoffset_t base;
|
|
2705
|
+
|
|
2706
|
+
check_field(td, id, required, base);
|
|
2707
|
+
return verify_string(td->buf, td->end, base, read_uoffset(td->buf, base));
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
int flatcc_verify_vector_field(flatcc_table_verifier_descriptor_t *td,
|
|
2711
|
+
voffset_t id, int required, size_t elem_size,
|
|
2712
|
+
uint16_t align, size_t max_count) {
|
|
2713
|
+
uoffset_t base;
|
|
2714
|
+
|
|
2715
|
+
check_field(td, id, required, base);
|
|
2716
|
+
return verify_vector(td->buf, td->end, base, read_uoffset(td->buf, base),
|
|
2717
|
+
(uoffset_t)elem_size, align, (uoffset_t)max_count);
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
int flatcc_verify_string_vector_field(flatcc_table_verifier_descriptor_t *td,
|
|
2721
|
+
voffset_t id, int required) {
|
|
2722
|
+
uoffset_t base;
|
|
2723
|
+
|
|
2724
|
+
check_field(td, id, required, base);
|
|
2725
|
+
return verify_string_vector(td->buf, td->end, base,
|
|
2726
|
+
read_uoffset(td->buf, base));
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
int flatcc_verify_table_field(flatcc_table_verifier_descriptor_t *td,
|
|
2730
|
+
voffset_t id, int required,
|
|
2731
|
+
flatcc_table_verifier_f tvf) {
|
|
2732
|
+
uoffset_t base;
|
|
2733
|
+
|
|
2734
|
+
check_field(td, id, required, base);
|
|
2735
|
+
return verify_table(td->buf, td->end, base, read_uoffset(td->buf, base),
|
|
2736
|
+
td->ttl, tvf);
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
int flatcc_verify_table_vector_field(flatcc_table_verifier_descriptor_t *td,
|
|
2740
|
+
voffset_t id, int required,
|
|
2741
|
+
flatcc_table_verifier_f tvf) {
|
|
2742
|
+
uoffset_t base;
|
|
2743
|
+
|
|
2744
|
+
check_field(td, id, required, base);
|
|
2745
|
+
return verify_table_vector(td->buf, td->end, base,
|
|
2746
|
+
read_uoffset(td->buf, base), td->ttl, tvf);
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
int flatcc_verify_union_table(flatcc_union_verifier_descriptor_t *ud,
|
|
2750
|
+
flatcc_table_verifier_f *tvf) {
|
|
2751
|
+
return verify_table(ud->buf, ud->end, ud->base, ud->offset, ud->ttl, tvf);
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
int flatcc_verify_union_struct(flatcc_union_verifier_descriptor_t *ud,
|
|
2755
|
+
size_t size, uint16_t align) {
|
|
2756
|
+
return verify_struct(ud->end, ud->base, ud->offset, (uoffset_t)size, align);
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
int flatcc_verify_union_string(flatcc_union_verifier_descriptor_t *ud) {
|
|
2760
|
+
return verify_string(ud->buf, ud->end, ud->base, ud->offset);
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
int flatcc_verify_buffer_header(const void *buf, size_t bufsiz,
|
|
2764
|
+
const char *fid) {
|
|
2765
|
+
thash_t id, id2;
|
|
2766
|
+
|
|
2767
|
+
verify_runtime(!(((size_t)buf) & (offset_size - 1)),
|
|
2768
|
+
flatcc_verify_error_runtime_buffer_header_not_aligned);
|
|
2769
|
+
/* -8 ensures no scalar or offset field size can overflow. */
|
|
2770
|
+
verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8,
|
|
2771
|
+
flatcc_verify_error_runtime_buffer_size_too_large);
|
|
2772
|
+
/*
|
|
2773
|
+
* Even if we specify no fid, the user might later. Therefore
|
|
2774
|
+
* require space for it. Not all buffer generators will take this
|
|
2775
|
+
* into account, so it is possible to fail an otherwise valid buffer
|
|
2776
|
+
* - but such buffers aren't safe.
|
|
2777
|
+
*/
|
|
2778
|
+
verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE,
|
|
2779
|
+
flatcc_verify_error_buffer_header_too_small);
|
|
2780
|
+
if (fid != 0) {
|
|
2781
|
+
id2 = read_thash_identifier(fid);
|
|
2782
|
+
id = read_thash(buf, offset_size);
|
|
2783
|
+
verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch);
|
|
2784
|
+
}
|
|
2785
|
+
return flatcc_verify_ok;
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
int flatcc_verify_typed_buffer_header(const void *buf, size_t bufsiz,
|
|
2789
|
+
flatbuffers_thash_t thash) {
|
|
2790
|
+
thash_t id, id2;
|
|
2791
|
+
|
|
2792
|
+
verify_runtime(!(((size_t)buf) & (offset_size - 1)),
|
|
2793
|
+
flatcc_verify_error_runtime_buffer_header_not_aligned);
|
|
2794
|
+
/* -8 ensures no scalar or offset field size can overflow. */
|
|
2795
|
+
verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8,
|
|
2796
|
+
flatcc_verify_error_runtime_buffer_size_too_large);
|
|
2797
|
+
/*
|
|
2798
|
+
* Even if we specify no fid, the user might later. Therefore
|
|
2799
|
+
* require space for it. Not all buffer generators will take this
|
|
2800
|
+
* into account, so it is possible to fail an otherwise valid buffer
|
|
2801
|
+
* - but such buffers aren't safe.
|
|
2802
|
+
*/
|
|
2803
|
+
verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE,
|
|
2804
|
+
flatcc_verify_error_buffer_header_too_small);
|
|
2805
|
+
if (thash != 0) {
|
|
2806
|
+
id2 = thash;
|
|
2807
|
+
id = read_thash(buf, offset_size);
|
|
2808
|
+
verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch);
|
|
2809
|
+
}
|
|
2810
|
+
return flatcc_verify_ok;
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
int flatcc_verify_struct_as_root(const void *buf, size_t bufsiz,
|
|
2814
|
+
const char *fid, size_t size, uint16_t align) {
|
|
2815
|
+
check_result(flatcc_verify_buffer_header(buf, bufsiz, fid));
|
|
2816
|
+
return verify_struct((uoffset_t)bufsiz, 0, read_uoffset(buf, 0),
|
|
2817
|
+
(uoffset_t)size, align);
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
int flatcc_verify_struct_as_typed_root(const void *buf, size_t bufsiz,
|
|
2821
|
+
flatbuffers_thash_t thash, size_t size,
|
|
2822
|
+
uint16_t align) {
|
|
2823
|
+
check_result(flatcc_verify_typed_buffer_header(buf, bufsiz, thash));
|
|
2824
|
+
return verify_struct((uoffset_t)bufsiz, 0, read_uoffset(buf, 0),
|
|
2825
|
+
(uoffset_t)size, align);
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
int flatcc_verify_table_as_root(const void *buf, size_t bufsiz, const char *fid,
|
|
2829
|
+
flatcc_table_verifier_f *tvf) {
|
|
2830
|
+
check_result(flatcc_verify_buffer_header(buf, (uoffset_t)bufsiz, fid));
|
|
2831
|
+
return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0),
|
|
2832
|
+
FLATCC_VERIFIER_MAX_LEVELS, tvf);
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
int flatcc_verify_table_as_typed_root(const void *buf, size_t bufsiz,
|
|
2836
|
+
flatbuffers_thash_t thash,
|
|
2837
|
+
flatcc_table_verifier_f *tvf) {
|
|
2838
|
+
check_result(
|
|
2839
|
+
flatcc_verify_typed_buffer_header(buf, (uoffset_t)bufsiz, thash));
|
|
2840
|
+
return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0),
|
|
2841
|
+
FLATCC_VERIFIER_MAX_LEVELS, tvf);
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
int flatcc_verify_struct_as_nested_root(flatcc_table_verifier_descriptor_t *td,
|
|
2845
|
+
voffset_t id, int required,
|
|
2846
|
+
const char *fid, size_t size,
|
|
2847
|
+
uint16_t align) {
|
|
2848
|
+
const uoffset_t *buf;
|
|
2849
|
+
uoffset_t bufsiz;
|
|
2850
|
+
|
|
2851
|
+
check_result(flatcc_verify_vector_field(td, id, required, align, 1,
|
|
2852
|
+
FLATBUFFERS_COUNT_MAX(1)));
|
|
2853
|
+
if (0 == (buf = get_field_ptr(td, id))) {
|
|
2854
|
+
return flatcc_verify_ok;
|
|
2855
|
+
}
|
|
2856
|
+
buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0));
|
|
2857
|
+
bufsiz = read_uoffset(buf, 0);
|
|
2858
|
+
++buf;
|
|
2859
|
+
return flatcc_verify_struct_as_root(buf, bufsiz, fid, size, align);
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
int flatcc_verify_table_as_nested_root(flatcc_table_verifier_descriptor_t *td,
|
|
2863
|
+
voffset_t id, int required,
|
|
2864
|
+
const char *fid, uint16_t align,
|
|
2865
|
+
flatcc_table_verifier_f tvf) {
|
|
2866
|
+
const uoffset_t *buf;
|
|
2867
|
+
uoffset_t bufsiz;
|
|
2868
|
+
|
|
2869
|
+
check_result(flatcc_verify_vector_field(td, id, required, align, 1,
|
|
2870
|
+
FLATBUFFERS_COUNT_MAX(1)));
|
|
2871
|
+
if (0 == (buf = get_field_ptr(td, id))) {
|
|
2872
|
+
return flatcc_verify_ok;
|
|
2873
|
+
}
|
|
2874
|
+
buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0));
|
|
2875
|
+
bufsiz = read_uoffset(buf, 0);
|
|
2876
|
+
++buf;
|
|
2877
|
+
/*
|
|
2878
|
+
* Don't verify nested buffers identifier - information is difficult to get
|
|
2879
|
+
* and might not be what is desired anyway. User can do it later.
|
|
2880
|
+
*/
|
|
2881
|
+
check_result(flatcc_verify_buffer_header(buf, bufsiz, fid));
|
|
2882
|
+
return verify_table(buf, bufsiz, 0, read_uoffset(buf, 0), td->ttl, tvf);
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
int flatcc_verify_union_field(flatcc_table_verifier_descriptor_t *td,
|
|
2886
|
+
voffset_t id, int required,
|
|
2887
|
+
flatcc_union_verifier_f uvf) {
|
|
2888
|
+
voffset_t vte_type, vte_table;
|
|
2889
|
+
const uint8_t *type;
|
|
2890
|
+
uoffset_t base;
|
|
2891
|
+
flatcc_union_verifier_descriptor_t ud;
|
|
2892
|
+
|
|
2893
|
+
if (0 == (vte_type = read_vt_entry(td, id - 1))) {
|
|
2894
|
+
vte_table = read_vt_entry(td, id);
|
|
2895
|
+
verify(vte_table == 0,
|
|
2896
|
+
flatcc_verify_error_union_cannot_have_a_table_without_a_type);
|
|
2897
|
+
verify(!required,
|
|
2898
|
+
flatcc_verify_error_type_field_absent_from_required_union_field);
|
|
2899
|
+
return flatcc_verify_ok;
|
|
2900
|
+
}
|
|
2901
|
+
/* No need to check required here. */
|
|
2902
|
+
check_result(verify_field(td, id - 1, 0, 1, 1));
|
|
2903
|
+
/* Only now is it safe to read the type. */
|
|
2904
|
+
vte_table = read_vt_entry(td, id);
|
|
2905
|
+
type = (const uint8_t *)td->buf + td->table + vte_type;
|
|
2906
|
+
verify(*type || vte_table == 0,
|
|
2907
|
+
flatcc_verify_error_union_type_NONE_cannot_have_a_value);
|
|
2908
|
+
|
|
2909
|
+
if (*type == 0) {
|
|
2910
|
+
return flatcc_verify_ok;
|
|
2911
|
+
}
|
|
2912
|
+
check_field(td, id, required, base);
|
|
2913
|
+
ud.buf = td->buf;
|
|
2914
|
+
ud.end = td->end;
|
|
2915
|
+
ud.ttl = td->ttl;
|
|
2916
|
+
ud.base = base;
|
|
2917
|
+
ud.offset = read_uoffset(td->buf, base);
|
|
2918
|
+
ud.type = *type;
|
|
2919
|
+
return uvf(&ud);
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
int flatcc_verify_union_vector_field(flatcc_table_verifier_descriptor_t *td,
|
|
2923
|
+
flatbuffers_voffset_t id, int required,
|
|
2924
|
+
flatcc_union_verifier_f uvf) {
|
|
2925
|
+
voffset_t vte_type, vte_table;
|
|
2926
|
+
const uoffset_t *buf;
|
|
2927
|
+
const utype_t *types;
|
|
2928
|
+
uoffset_t count, base;
|
|
2929
|
+
|
|
2930
|
+
if (0 == (vte_type = read_vt_entry(td, id - 1))) {
|
|
2931
|
+
if (0 == (vte_table = read_vt_entry(td, id))) {
|
|
2932
|
+
verify(
|
|
2933
|
+
!required,
|
|
2934
|
+
flatcc_verify_error_type_field_absent_from_required_union_vector_field);
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
check_result(flatcc_verify_vector_field(td, id - 1, required, utype_size,
|
|
2938
|
+
utype_size,
|
|
2939
|
+
FLATBUFFERS_COUNT_MAX(utype_size)));
|
|
2940
|
+
if (0 == (buf = get_field_ptr(td, id - 1))) {
|
|
2941
|
+
return flatcc_verify_ok;
|
|
2942
|
+
}
|
|
2943
|
+
buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0));
|
|
2944
|
+
count = read_uoffset(buf, 0);
|
|
2945
|
+
++buf;
|
|
2946
|
+
types = (utype_t *)buf;
|
|
2947
|
+
|
|
2948
|
+
check_field(td, id, required, base);
|
|
2949
|
+
return verify_union_vector(td->buf, td->end, base,
|
|
2950
|
+
read_uoffset(td->buf, base), count, types, td->ttl,
|
|
2951
|
+
uvf);
|
|
2952
|
+
}
|
|
2953
|
+
/*
|
|
2954
|
+
* Optional file that can be included in runtime library to support DAG
|
|
2955
|
+
* cloning with the builder and may also be used for custom purposes
|
|
2956
|
+
* standalone. See also comments in `flatcc/flatcc_builder.h`.
|
|
2957
|
+
*
|
|
2958
|
+
* Note that dynamic construction takes place and that large offset
|
|
2959
|
+
* vectors might consume significant space if there are not many shared
|
|
2960
|
+
* references. In the basic use case no allocation takes place because a
|
|
2961
|
+
* few references can be held using only a small stack allocated hash
|
|
2962
|
+
* table.
|
|
2963
|
+
*/
|
|
2964
|
+
|
|
2965
|
+
#include <stdlib.h>
|
|
2966
|
+
#include <string.h>
|
|
2967
|
+
|
|
2968
|
+
#include "flatcc/flatcc_alloc.h"
|
|
2969
|
+
#include "flatcc/flatcc_assert.h"
|
|
2970
|
+
#include "flatcc/flatcc_refmap.h"
|
|
2971
|
+
#include "flatcc/flatcc_rtconfig.h"
|
|
2972
|
+
|
|
2973
|
+
#define _flatcc_refmap_calloc FLATCC_CALLOC
|
|
2974
|
+
#define _flatcc_refmap_free FLATCC_FREE
|
|
2975
|
+
|
|
2976
|
+
/* Can be used as a primitive defense against collision attacks. */
|
|
2977
|
+
#ifdef FLATCC_HASH_SEED
|
|
2978
|
+
#define _flatcc_refmap_seed FLATCC_HASH_SEED
|
|
2979
|
+
#else
|
|
2980
|
+
#define _flatcc_refmap_seed 0x2f693b52
|
|
2981
|
+
#endif
|
|
2982
|
+
|
|
2983
|
+
static inline size_t _flatcc_refmap_above_load_factor(size_t count,
|
|
2984
|
+
size_t buckets) {
|
|
2985
|
+
static const size_t d = 256;
|
|
2986
|
+
static const size_t n = (size_t)((FLATCC_REFMAP_LOAD_FACTOR) * 256.0f);
|
|
2987
|
+
|
|
2988
|
+
return count >= buckets * n / d;
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
#define _flatcc_refmap_probe(k, i, N) ((k + i) & N)
|
|
2992
|
+
|
|
2993
|
+
void flatcc_refmap_clear(flatcc_refmap_t *refmap) {
|
|
2994
|
+
if (refmap->table && refmap->table != refmap->min_table) {
|
|
2995
|
+
_flatcc_refmap_free(refmap->table);
|
|
2996
|
+
}
|
|
2997
|
+
flatcc_refmap_init(refmap);
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
static inline size_t _flatcc_refmap_hash(const void *src) {
|
|
3001
|
+
/* MurmurHash3 64-bit finalizer */
|
|
3002
|
+
uint64_t x;
|
|
3003
|
+
|
|
3004
|
+
x = (uint64_t)((size_t)src) ^ _flatcc_refmap_seed;
|
|
3005
|
+
|
|
3006
|
+
x ^= x >> 33;
|
|
3007
|
+
x *= 0xff51afd7ed558ccdULL;
|
|
3008
|
+
x ^= x >> 33;
|
|
3009
|
+
x *= 0xc4ceb9fe1a85ec53ULL;
|
|
3010
|
+
x ^= x >> 33;
|
|
3011
|
+
return (size_t)x;
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
void flatcc_refmap_reset(flatcc_refmap_t *refmap) {
|
|
3015
|
+
if (refmap->count) {
|
|
3016
|
+
memset(refmap->table, 0, sizeof(refmap->table[0]) * refmap->buckets);
|
|
3017
|
+
}
|
|
3018
|
+
refmap->count = 0;
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
/*
|
|
3022
|
+
* Technically resize also supports shrinking which may be useful for
|
|
3023
|
+
* adapations, but the current hash table never deletes individual items.
|
|
3024
|
+
*/
|
|
3025
|
+
int flatcc_refmap_resize(flatcc_refmap_t *refmap, size_t count) {
|
|
3026
|
+
const size_t min_buckets =
|
|
3027
|
+
sizeof(refmap->min_table) / sizeof(refmap->min_table[0]);
|
|
3028
|
+
|
|
3029
|
+
size_t i;
|
|
3030
|
+
size_t buckets;
|
|
3031
|
+
size_t buckets_old;
|
|
3032
|
+
struct flatcc_refmap_item *T_old;
|
|
3033
|
+
|
|
3034
|
+
if (count < refmap->count) {
|
|
3035
|
+
count = refmap->count;
|
|
3036
|
+
}
|
|
3037
|
+
buckets = min_buckets;
|
|
3038
|
+
|
|
3039
|
+
while (_flatcc_refmap_above_load_factor(count, buckets)) {
|
|
3040
|
+
buckets *= 2;
|
|
3041
|
+
}
|
|
3042
|
+
if (refmap->buckets == buckets) {
|
|
3043
|
+
return 0;
|
|
3044
|
+
}
|
|
3045
|
+
T_old = refmap->table;
|
|
3046
|
+
buckets_old = refmap->buckets;
|
|
3047
|
+
if (buckets == min_buckets) {
|
|
3048
|
+
memset(refmap->min_table, 0, sizeof(refmap->min_table));
|
|
3049
|
+
refmap->table = refmap->min_table;
|
|
3050
|
+
} else {
|
|
3051
|
+
refmap->table = _flatcc_refmap_calloc(buckets, sizeof(refmap->table[0]));
|
|
3052
|
+
if (refmap->table == 0) {
|
|
3053
|
+
refmap->table = T_old;
|
|
3054
|
+
FLATCC_ASSERT(0); /* out of memory */
|
|
3055
|
+
return -1;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
refmap->buckets = buckets;
|
|
3059
|
+
refmap->count = 0;
|
|
3060
|
+
for (i = 0; i < buckets_old; ++i) {
|
|
3061
|
+
if (T_old[i].src) {
|
|
3062
|
+
flatcc_refmap_insert(refmap, T_old[i].src, T_old[i].ref);
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
if (T_old && T_old != refmap->min_table) {
|
|
3066
|
+
_flatcc_refmap_free(T_old);
|
|
3067
|
+
}
|
|
3068
|
+
return 0;
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
flatcc_refmap_ref_t flatcc_refmap_insert(flatcc_refmap_t *refmap,
|
|
3072
|
+
const void *src,
|
|
3073
|
+
flatcc_refmap_ref_t ref) {
|
|
3074
|
+
struct flatcc_refmap_item *T;
|
|
3075
|
+
size_t N, i, j, k;
|
|
3076
|
+
|
|
3077
|
+
if (src == 0) return ref;
|
|
3078
|
+
if (_flatcc_refmap_above_load_factor(refmap->count, refmap->buckets)) {
|
|
3079
|
+
if (flatcc_refmap_resize(refmap, refmap->count * 2)) {
|
|
3080
|
+
return flatcc_refmap_not_found; /* alloc failed */
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
T = refmap->table;
|
|
3084
|
+
N = refmap->buckets - 1;
|
|
3085
|
+
k = _flatcc_refmap_hash(src);
|
|
3086
|
+
i = 0;
|
|
3087
|
+
j = _flatcc_refmap_probe(k, i, N);
|
|
3088
|
+
while (T[j].src) {
|
|
3089
|
+
if (T[j].src == src) {
|
|
3090
|
+
return T[j].ref = ref;
|
|
3091
|
+
}
|
|
3092
|
+
++i;
|
|
3093
|
+
j = _flatcc_refmap_probe(k, i, N);
|
|
3094
|
+
}
|
|
3095
|
+
++refmap->count;
|
|
3096
|
+
T[j].src = src;
|
|
3097
|
+
return T[j].ref = ref;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
flatcc_refmap_ref_t flatcc_refmap_find(flatcc_refmap_t *refmap,
|
|
3101
|
+
const void *src) {
|
|
3102
|
+
struct flatcc_refmap_item *T;
|
|
3103
|
+
size_t N, i, j, k;
|
|
3104
|
+
|
|
3105
|
+
if (refmap->count == 0) {
|
|
3106
|
+
return flatcc_refmap_not_found;
|
|
3107
|
+
}
|
|
3108
|
+
T = refmap->table;
|
|
3109
|
+
N = refmap->buckets - 1;
|
|
3110
|
+
k = _flatcc_refmap_hash(src);
|
|
3111
|
+
i = 0;
|
|
3112
|
+
j = _flatcc_refmap_probe(k, i, N);
|
|
3113
|
+
while (T[j].src) {
|
|
3114
|
+
if (T[j].src == src) return T[j].ref;
|
|
3115
|
+
++i;
|
|
3116
|
+
j = _flatcc_refmap_probe(k, i, N);
|
|
3117
|
+
}
|
|
3118
|
+
return flatcc_refmap_not_found;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
/*
|
|
3122
|
+
* To run test from project root:
|
|
3123
|
+
*
|
|
3124
|
+
* cc -D FLATCC_REFMAP_TEST -I include src/runtime/refmap.c -o test_refmap &&
|
|
3125
|
+
* ./test_refmap
|
|
3126
|
+
*
|
|
3127
|
+
*/
|
|
3128
|
+
#ifdef FLATCC_REFMAP_TEST
|
|
3129
|
+
|
|
3130
|
+
#include <stdio.h>
|
|
3131
|
+
|
|
3132
|
+
#ifndef FLATCC_REFMAP_H
|
|
3133
|
+
#include "flatcc/flatcc_refmap.h"
|
|
3134
|
+
#endif
|
|
3135
|
+
|
|
3136
|
+
#define test(x) \
|
|
3137
|
+
do { \
|
|
3138
|
+
if (!(x)) { \
|
|
3139
|
+
fprintf(stderr, "%02d: refmap test failed\n", __LINE__); \
|
|
3140
|
+
exit(-1); \
|
|
3141
|
+
} \
|
|
3142
|
+
} while (0)
|
|
3143
|
+
#define test_start() fprintf(stderr, "starting refmap test ...\n")
|
|
3144
|
+
#define test_ok() fprintf(stderr, "refmap test succeeded\n")
|
|
3145
|
+
|
|
3146
|
+
int main() {
|
|
3147
|
+
int i;
|
|
3148
|
+
int data[1000];
|
|
3149
|
+
int a = 1;
|
|
3150
|
+
int b = 2;
|
|
3151
|
+
int c = 3;
|
|
3152
|
+
flatcc_refmap_t refmap;
|
|
3153
|
+
|
|
3154
|
+
flatcc_refmap_init(&refmap);
|
|
3155
|
+
|
|
3156
|
+
test(flatcc_refmap_find(&refmap, &a) == flatcc_refmap_not_found);
|
|
3157
|
+
test(flatcc_refmap_find(&refmap, &b) == flatcc_refmap_not_found);
|
|
3158
|
+
test(flatcc_refmap_find(&refmap, &c) == flatcc_refmap_not_found);
|
|
3159
|
+
test(flatcc_refmap_find(&refmap, 0) == flatcc_refmap_not_found);
|
|
3160
|
+
test(flatcc_refmap_find(&refmap, &a) == 0);
|
|
3161
|
+
|
|
3162
|
+
test(flatcc_refmap_insert(&refmap, &a, 42) == 42);
|
|
3163
|
+
test(flatcc_refmap_find(&refmap, &a) == 42);
|
|
3164
|
+
test(flatcc_refmap_find(&refmap, &b) == flatcc_refmap_not_found);
|
|
3165
|
+
test(flatcc_refmap_find(&refmap, &c) == flatcc_refmap_not_found);
|
|
3166
|
+
test(flatcc_refmap_insert(&refmap, &a, 42) == 42);
|
|
3167
|
+
test(flatcc_refmap_find(&refmap, &a) == 42);
|
|
3168
|
+
test(refmap.count == 1);
|
|
3169
|
+
test(flatcc_refmap_insert(&refmap, &a, 43) == 43);
|
|
3170
|
+
test(flatcc_refmap_find(&refmap, &a) == 43);
|
|
3171
|
+
test(refmap.count == 1);
|
|
3172
|
+
test(flatcc_refmap_insert(&refmap, &b, -10) == -10);
|
|
3173
|
+
test(flatcc_refmap_insert(&refmap, &c, 100) == 100);
|
|
3174
|
+
test(refmap.count == 3);
|
|
3175
|
+
test(flatcc_refmap_find(&refmap, &a) == 43);
|
|
3176
|
+
test(flatcc_refmap_find(&refmap, &b) == -10);
|
|
3177
|
+
test(flatcc_refmap_find(&refmap, &c) == 100);
|
|
3178
|
+
|
|
3179
|
+
test(flatcc_refmap_insert(&refmap, 0, 1000) == 1000);
|
|
3180
|
+
test(flatcc_refmap_find(&refmap, 0) == 0);
|
|
3181
|
+
test(refmap.count == 3);
|
|
3182
|
+
|
|
3183
|
+
test(flatcc_refmap_insert(&refmap, &b, 0) == 0);
|
|
3184
|
+
test(flatcc_refmap_find(&refmap, &b) == 0);
|
|
3185
|
+
test(refmap.count == 3);
|
|
3186
|
+
|
|
3187
|
+
flatcc_refmap_reset(&refmap);
|
|
3188
|
+
test(refmap.count == 0);
|
|
3189
|
+
test(refmap.buckets > 0);
|
|
3190
|
+
for (i = 0; i < 1000; ++i) {
|
|
3191
|
+
test(flatcc_refmap_insert(&refmap, data + i, i + 42) == i + 42);
|
|
3192
|
+
}
|
|
3193
|
+
test(refmap.count == 1000);
|
|
3194
|
+
for (i = 0; i < 1000; ++i) {
|
|
3195
|
+
test(flatcc_refmap_find(&refmap, data + i) == i + 42);
|
|
3196
|
+
}
|
|
3197
|
+
flatcc_refmap_clear(&refmap);
|
|
3198
|
+
test(refmap.count == 0);
|
|
3199
|
+
test(refmap.buckets == 0);
|
|
3200
|
+
test_ok();
|
|
3201
|
+
return 0;
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3204
|
+
#endif /* FLATCC_REFMAP_TEST */
|