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.
Files changed (246) hide show
  1. snowflake/connector/__init__.py +96 -0
  2. snowflake/connector/_query_context_cache.py +276 -0
  3. snowflake/connector/_sql_util.py +48 -0
  4. snowflake/connector/_utils.py +70 -0
  5. snowflake/connector/arrow_context.py +203 -0
  6. snowflake/connector/auth/__init__.py +53 -0
  7. snowflake/connector/auth/_auth.py +586 -0
  8. snowflake/connector/auth/_http_server.py +220 -0
  9. snowflake/connector/auth/_oauth_base.py +400 -0
  10. snowflake/connector/auth/by_plugin.py +219 -0
  11. snowflake/connector/auth/default.py +36 -0
  12. snowflake/connector/auth/idtoken.py +72 -0
  13. snowflake/connector/auth/keypair.py +222 -0
  14. snowflake/connector/auth/no_auth.py +39 -0
  15. snowflake/connector/auth/oauth.py +49 -0
  16. snowflake/connector/auth/oauth_code.py +479 -0
  17. snowflake/connector/auth/oauth_credentials.py +66 -0
  18. snowflake/connector/auth/okta.py +335 -0
  19. snowflake/connector/auth/pat.py +39 -0
  20. snowflake/connector/auth/usrpwdmfa.py +69 -0
  21. snowflake/connector/auth/webbrowser.py +502 -0
  22. snowflake/connector/auth/workload_identity.py +94 -0
  23. snowflake/connector/azure_storage_client.py +276 -0
  24. snowflake/connector/backoff_policies.py +141 -0
  25. snowflake/connector/bind_upload_agent.py +89 -0
  26. snowflake/connector/cache.py +696 -0
  27. snowflake/connector/compat.py +127 -0
  28. snowflake/connector/config_manager.py +496 -0
  29. snowflake/connector/connection.py +2273 -0
  30. snowflake/connector/connection_diagnostic.py +776 -0
  31. snowflake/connector/constants.py +442 -0
  32. snowflake/connector/converter.py +785 -0
  33. snowflake/connector/converter_issue23517.py +87 -0
  34. snowflake/connector/converter_null.py +14 -0
  35. snowflake/connector/converter_snowsql.py +205 -0
  36. snowflake/connector/cursor.py +1951 -0
  37. snowflake/connector/dbapi.py +53 -0
  38. snowflake/connector/description.py +19 -0
  39. snowflake/connector/direct_file_operation_utils.py +88 -0
  40. snowflake/connector/encryption_util.py +220 -0
  41. snowflake/connector/errorcode.py +91 -0
  42. snowflake/connector/errors.py +615 -0
  43. snowflake/connector/externals_utils/__init__.py +0 -0
  44. snowflake/connector/externals_utils/externals_setup.py +27 -0
  45. snowflake/connector/feature.py +4 -0
  46. snowflake/connector/file_compression_type.py +118 -0
  47. snowflake/connector/file_lock.py +72 -0
  48. snowflake/connector/file_transfer_agent.py +1215 -0
  49. snowflake/connector/file_util.py +153 -0
  50. snowflake/connector/gcs_storage_client.py +474 -0
  51. snowflake/connector/gzip_decoder.py +85 -0
  52. snowflake/connector/local_storage_client.py +90 -0
  53. snowflake/connector/log_configuration.py +60 -0
  54. snowflake/connector/logging_utils/__init__.py +0 -0
  55. snowflake/connector/logging_utils/filters.py +72 -0
  56. snowflake/connector/nanoarrow_arrow_iterator.cp313-win_amd64.pyd +0 -0
  57. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
  58. snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
  59. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
  60. snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
  61. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
  62. snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
  63. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +557 -0
  64. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
  65. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
  66. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
  67. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1005 -0
  68. snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +127 -0
  69. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
  70. snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
  71. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
  72. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
  73. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
  74. snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
  75. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
  76. snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
  77. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
  78. snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
  79. snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
  80. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
  81. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
  82. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +71 -0
  83. snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +56 -0
  84. snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
  85. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
  86. snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
  87. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
  88. snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
  89. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
  90. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
  91. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
  92. snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
  93. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
  94. snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
  95. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
  96. snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
  97. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
  98. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
  99. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
  100. snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
  101. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
  102. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +65 -0
  103. snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
  104. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
  105. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
  106. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
  107. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
  108. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
  109. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
  110. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
  111. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
  112. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
  113. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
  114. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
  115. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
  116. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
  117. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
  118. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
  119. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
  120. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
  121. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
  122. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
  123. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
  124. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
  125. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
  126. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
  127. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
  128. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
  129. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
  130. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
  131. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
  132. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
  133. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
  134. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
  135. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
  136. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
  137. snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
  138. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
  139. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
  140. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
  141. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +256 -0
  142. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
  143. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
  144. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
  145. snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
  146. snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
  147. snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
  148. snowflake/connector/network.py +1297 -0
  149. snowflake/connector/ocsp_asn1crypto.py +447 -0
  150. snowflake/connector/ocsp_snowflake.py +1883 -0
  151. snowflake/connector/options.py +131 -0
  152. snowflake/connector/pandas_tools.py +732 -0
  153. snowflake/connector/proxy.py +43 -0
  154. snowflake/connector/py.typed +0 -0
  155. snowflake/connector/result_batch.py +786 -0
  156. snowflake/connector/result_set.py +319 -0
  157. snowflake/connector/s3_storage_client.py +605 -0
  158. snowflake/connector/secret_detector.py +181 -0
  159. snowflake/connector/sf_dirs.py +64 -0
  160. snowflake/connector/sfbinaryformat.py +35 -0
  161. snowflake/connector/sfdatetime.py +345 -0
  162. snowflake/connector/snow_logging.py +144 -0
  163. snowflake/connector/sqlstate.py +9 -0
  164. snowflake/connector/ssd_internal_keys.py +30 -0
  165. snowflake/connector/ssl_wrap_socket.py +134 -0
  166. snowflake/connector/storage_client.py +478 -0
  167. snowflake/connector/telemetry.py +249 -0
  168. snowflake/connector/telemetry_oob.py +543 -0
  169. snowflake/connector/test_util.py +30 -0
  170. snowflake/connector/time_util.py +159 -0
  171. snowflake/connector/token_cache.py +402 -0
  172. snowflake/connector/tool/__init__.py +0 -0
  173. snowflake/connector/tool/dump_certs.py +57 -0
  174. snowflake/connector/tool/dump_ocsp_response.py +139 -0
  175. snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
  176. snowflake/connector/tool/probe_connection.py +69 -0
  177. snowflake/connector/url_util.py +49 -0
  178. snowflake/connector/util_text.py +301 -0
  179. snowflake/connector/vendored/__init__.py +3 -0
  180. snowflake/connector/vendored/requests/LICENSE +175 -0
  181. snowflake/connector/vendored/requests/__init__.py +169 -0
  182. snowflake/connector/vendored/requests/__version__.py +14 -0
  183. snowflake/connector/vendored/requests/_internal_utils.py +50 -0
  184. snowflake/connector/vendored/requests/adapters.py +537 -0
  185. snowflake/connector/vendored/requests/api.py +157 -0
  186. snowflake/connector/vendored/requests/auth.py +315 -0
  187. snowflake/connector/vendored/requests/certs.py +17 -0
  188. snowflake/connector/vendored/requests/compat.py +79 -0
  189. snowflake/connector/vendored/requests/cookies.py +561 -0
  190. snowflake/connector/vendored/requests/exceptions.py +140 -0
  191. snowflake/connector/vendored/requests/help.py +134 -0
  192. snowflake/connector/vendored/requests/hooks.py +33 -0
  193. snowflake/connector/vendored/requests/models.py +1033 -0
  194. snowflake/connector/vendored/requests/sessions.py +833 -0
  195. snowflake/connector/vendored/requests/status_codes.py +128 -0
  196. snowflake/connector/vendored/requests/structures.py +99 -0
  197. snowflake/connector/vendored/requests/utils.py +1093 -0
  198. snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
  199. snowflake/connector/vendored/urllib3/__init__.py +85 -0
  200. snowflake/connector/vendored/urllib3/_collections.py +355 -0
  201. snowflake/connector/vendored/urllib3/_version.py +2 -0
  202. snowflake/connector/vendored/urllib3/connection.py +572 -0
  203. snowflake/connector/vendored/urllib3/connectionpool.py +1137 -0
  204. snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
  205. snowflake/connector/vendored/urllib3/contrib/_appengine_environ.py +36 -0
  206. snowflake/connector/vendored/urllib3/contrib/_securetransport/__init__.py +0 -0
  207. snowflake/connector/vendored/urllib3/contrib/_securetransport/bindings.py +519 -0
  208. snowflake/connector/vendored/urllib3/contrib/_securetransport/low_level.py +397 -0
  209. snowflake/connector/vendored/urllib3/contrib/appengine.py +314 -0
  210. snowflake/connector/vendored/urllib3/contrib/ntlmpool.py +130 -0
  211. snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +509 -0
  212. snowflake/connector/vendored/urllib3/contrib/securetransport.py +920 -0
  213. snowflake/connector/vendored/urllib3/contrib/socks.py +216 -0
  214. snowflake/connector/vendored/urllib3/exceptions.py +323 -0
  215. snowflake/connector/vendored/urllib3/fields.py +274 -0
  216. snowflake/connector/vendored/urllib3/filepost.py +98 -0
  217. snowflake/connector/vendored/urllib3/packages/__init__.py +0 -0
  218. snowflake/connector/vendored/urllib3/packages/backports/__init__.py +0 -0
  219. snowflake/connector/vendored/urllib3/packages/backports/makefile.py +51 -0
  220. snowflake/connector/vendored/urllib3/packages/backports/weakref_finalize.py +155 -0
  221. snowflake/connector/vendored/urllib3/packages/six.py +1076 -0
  222. snowflake/connector/vendored/urllib3/poolmanager.py +540 -0
  223. snowflake/connector/vendored/urllib3/request.py +191 -0
  224. snowflake/connector/vendored/urllib3/response.py +885 -0
  225. snowflake/connector/vendored/urllib3/util/__init__.py +49 -0
  226. snowflake/connector/vendored/urllib3/util/connection.py +156 -0
  227. snowflake/connector/vendored/urllib3/util/proxy.py +57 -0
  228. snowflake/connector/vendored/urllib3/util/queue.py +22 -0
  229. snowflake/connector/vendored/urllib3/util/request.py +146 -0
  230. snowflake/connector/vendored/urllib3/util/response.py +107 -0
  231. snowflake/connector/vendored/urllib3/util/retry.py +620 -0
  232. snowflake/connector/vendored/urllib3/util/ssl_.py +495 -0
  233. snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
  234. snowflake/connector/vendored/urllib3/util/ssltransport.py +221 -0
  235. snowflake/connector/vendored/urllib3/util/timeout.py +271 -0
  236. snowflake/connector/vendored/urllib3/util/url.py +435 -0
  237. snowflake/connector/vendored/urllib3/util/wait.py +152 -0
  238. snowflake/connector/version.py +3 -0
  239. snowflake/connector/wif_util.py +407 -0
  240. snowflake_connector_python-3.16.0.dist-info/METADATA +1475 -0
  241. snowflake_connector_python-3.16.0.dist-info/RECORD +246 -0
  242. snowflake_connector_python-3.16.0.dist-info/WHEEL +5 -0
  243. snowflake_connector_python-3.16.0.dist-info/entry_points.txt +4 -0
  244. snowflake_connector_python-3.16.0.dist-info/licenses/LICENSE.txt +202 -0
  245. snowflake_connector_python-3.16.0.dist-info/licenses/NOTICE +8 -0
  246. 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 */