librats 1.0.2 → 2.1.4

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 (313) hide show
  1. package/README.md +137 -332
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +271 -696
  4. package/lib/index.js +383 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +396 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +731 -0
  10. package/native-src/src/librats/bindings/rats.h +352 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +42 -0
  73. package/native-src/src/librats/core/types.h +93 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/config.h +110 -0
  144. package/native-src/src/librats/node/dial_service.h +54 -0
  145. package/native-src/src/librats/node/dialer.cpp +264 -0
  146. package/native-src/src/librats/node/dialer.h +188 -0
  147. package/native-src/src/librats/node/host_events.h +26 -0
  148. package/native-src/src/librats/node/identify.cpp +130 -0
  149. package/native-src/src/librats/node/identify.h +71 -0
  150. package/native-src/src/librats/node/nat_status.cpp +103 -0
  151. package/native-src/src/librats/node/nat_status.h +118 -0
  152. package/native-src/src/librats/node/node.cpp +826 -0
  153. package/native-src/src/librats/node/node.h +333 -0
  154. package/native-src/src/librats/node/node_context.h +33 -0
  155. package/native-src/src/librats/node/peer_network.h +91 -0
  156. package/native-src/src/librats/peer/peer.h +49 -0
  157. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  158. package/native-src/src/librats/peer/peer_book.h +88 -0
  159. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  160. package/native-src/src/librats/peer/peer_id.h +62 -0
  161. package/native-src/src/librats/peer/peer_info.h +37 -0
  162. package/native-src/src/librats/peer/peer_table.cpp +137 -0
  163. package/native-src/src/librats/peer/peer_table.h +148 -0
  164. package/native-src/src/librats/security/handshaker.h +66 -0
  165. package/native-src/src/librats/security/identity.h +43 -0
  166. package/native-src/src/librats/security/noise_security.cpp +122 -0
  167. package/native-src/src/librats/security/noise_security.h +37 -0
  168. package/native-src/src/librats/security/plaintext_security.h +106 -0
  169. package/native-src/src/librats/security/session.h +37 -0
  170. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  171. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  172. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  173. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  174. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  176. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  177. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  178. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  179. package/native-src/src/librats/subsystems/hole_punch.cpp +532 -0
  180. package/native-src/src/librats/subsystems/hole_punch.h +266 -0
  181. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  182. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  184. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  185. package/native-src/src/librats/subsystems/message_json.h +88 -0
  186. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  188. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  189. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  190. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  192. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  193. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  194. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  195. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  196. package/native-src/src/librats/transport/connection.cpp +343 -0
  197. package/native-src/src/librats/transport/connection.h +283 -0
  198. package/native-src/src/librats/transport/link.h +96 -0
  199. package/native-src/src/librats/transport/reactor.cpp +540 -0
  200. package/native-src/src/librats/transport/reactor.h +224 -0
  201. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  202. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  203. package/native-src/src/librats/transport/tcp_link.h +43 -0
  204. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  205. package/native-src/src/librats/transport/udp_mux.h +363 -0
  206. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  207. package/native-src/src/librats/transport/udp_packet.h +190 -0
  208. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  209. package/native-src/src/librats/transport/udp_stream.h +614 -0
  210. package/native-src/src/librats/util/features.h.in +51 -0
  211. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  212. package/native-src/src/librats/util/fs.h +136 -0
  213. package/native-src/src/librats/util/json.cpp +1002 -0
  214. package/native-src/src/librats/util/json.h +444 -0
  215. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  216. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  217. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  218. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  219. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  220. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  221. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  222. package/native-src/src/librats/util/rats_export.h +69 -0
  223. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  224. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  225. package/native-src/src/librats/wire/frame.cpp +76 -0
  226. package/native-src/src/librats/wire/frame.h +110 -0
  227. package/native-src/src/librats/wire/message_router.cpp +45 -0
  228. package/native-src/src/librats/wire/message_router.h +47 -0
  229. package/package.json +5 -4
  230. package/scripts/build-librats.js +1 -0
  231. package/scripts/postinstall.js +3 -3
  232. package/scripts/prepare-package.js +4 -4
  233. package/scripts/verify-installation.js +63 -105
  234. package/src/librats_node.cpp +1042 -1324
  235. package/native-src/src/bencode.cpp +0 -485
  236. package/native-src/src/bencode.h +0 -145
  237. package/native-src/src/bittorrent.cpp +0 -14
  238. package/native-src/src/bittorrent.h +0 -74
  239. package/native-src/src/bt_bitfield.cpp +0 -372
  240. package/native-src/src/bt_bitfield.h +0 -316
  241. package/native-src/src/bt_choker.cpp +0 -228
  242. package/native-src/src/bt_choker.h +0 -147
  243. package/native-src/src/bt_client.cpp +0 -1047
  244. package/native-src/src/bt_client.h +0 -445
  245. package/native-src/src/bt_create_torrent.cpp +0 -677
  246. package/native-src/src/bt_create_torrent.h +0 -473
  247. package/native-src/src/bt_extension.cpp +0 -469
  248. package/native-src/src/bt_extension.h +0 -309
  249. package/native-src/src/bt_file_storage.cpp +0 -261
  250. package/native-src/src/bt_file_storage.h +0 -298
  251. package/native-src/src/bt_handshake.cpp +0 -134
  252. package/native-src/src/bt_handshake.h +0 -157
  253. package/native-src/src/bt_messages.cpp +0 -364
  254. package/native-src/src/bt_messages.h +0 -324
  255. package/native-src/src/bt_network.cpp +0 -1007
  256. package/native-src/src/bt_network.h +0 -417
  257. package/native-src/src/bt_peer_connection.cpp +0 -742
  258. package/native-src/src/bt_peer_connection.h +0 -592
  259. package/native-src/src/bt_piece_picker.cpp +0 -786
  260. package/native-src/src/bt_piece_picker.h +0 -473
  261. package/native-src/src/bt_resume_data.cpp +0 -410
  262. package/native-src/src/bt_resume_data.h +0 -249
  263. package/native-src/src/bt_torrent.cpp +0 -2120
  264. package/native-src/src/bt_torrent.h +0 -641
  265. package/native-src/src/bt_torrent_info.cpp +0 -659
  266. package/native-src/src/bt_torrent_info.h +0 -418
  267. package/native-src/src/bt_types.h +0 -621
  268. package/native-src/src/chained_send_buffer.cpp +0 -75
  269. package/native-src/src/chained_send_buffer.h +0 -137
  270. package/native-src/src/crypto/hkdf.c +0 -266
  271. package/native-src/src/crypto/poly1305.h +0 -36
  272. package/native-src/src/dht.cpp +0 -3311
  273. package/native-src/src/dht.h +0 -717
  274. package/native-src/src/disk_io.cpp +0 -632
  275. package/native-src/src/disk_io.h +0 -315
  276. package/native-src/src/file_transfer.cpp +0 -1415
  277. package/native-src/src/file_transfer.h +0 -286
  278. package/native-src/src/fs.h +0 -108
  279. package/native-src/src/gossipsub.cpp +0 -1139
  280. package/native-src/src/gossipsub.h +0 -403
  281. package/native-src/src/ice.cpp +0 -893
  282. package/native-src/src/ice.h +0 -559
  283. package/native-src/src/json.hpp +0 -25526
  284. package/native-src/src/librats.cpp +0 -2378
  285. package/native-src/src/librats.h +0 -2324
  286. package/native-src/src/librats_bittorrent.cpp +0 -601
  287. package/native-src/src/librats_c.cpp +0 -1557
  288. package/native-src/src/librats_c.h +0 -323
  289. package/native-src/src/librats_discovery.cpp +0 -402
  290. package/native-src/src/librats_encryption.cpp +0 -275
  291. package/native-src/src/librats_file_transfer.cpp +0 -144
  292. package/native-src/src/librats_gossipsub.cpp +0 -289
  293. package/native-src/src/librats_ice.cpp +0 -213
  294. package/native-src/src/librats_log_macros.h +0 -36
  295. package/native-src/src/librats_logging.cpp +0 -173
  296. package/native-src/src/librats_mdns.cpp +0 -166
  297. package/native-src/src/librats_persistence.cpp +0 -796
  298. package/native-src/src/librats_portmap.cpp +0 -419
  299. package/native-src/src/librats_reconnection.cpp +0 -218
  300. package/native-src/src/librats_statistic.cpp +0 -105
  301. package/native-src/src/librats_storage.cpp +0 -189
  302. package/native-src/src/rats_export.h +0 -17
  303. package/native-src/src/receive_buffer.cpp +0 -82
  304. package/native-src/src/receive_buffer.h +0 -127
  305. package/native-src/src/socket.h +0 -228
  306. package/native-src/src/threadmanager.cpp +0 -105
  307. package/native-src/src/threadmanager.h +0 -53
  308. package/native-src/src/tracker.cpp +0 -1264
  309. package/native-src/src/tracker.h +0 -319
  310. package/native-src/src/turn.cpp +0 -762
  311. package/native-src/src/turn.h +0 -460
  312. package/native-src/src/wakeup_pipe.h +0 -60
  313. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -0,0 +1,437 @@
1
+ #include "librats/bittorrent/bencode.h"
2
+
3
+ #include <algorithm>
4
+ #include <limits>
5
+ #include <stdexcept>
6
+
7
+ namespace librats {
8
+
9
+ // =============================================================================
10
+ // Container boxing helpers — the only code aware of LIBRATS_BENCODE_BOXED_CONTAINERS
11
+ // =============================================================================
12
+
13
+ void BencodeValue::set_list(BencodeList l) {
14
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
15
+ value_ = std::make_shared<BencodeList>(std::move(l));
16
+ #else
17
+ value_ = std::move(l);
18
+ #endif
19
+ }
20
+
21
+ void BencodeValue::set_dict(BencodeDict d) {
22
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
23
+ value_ = std::make_shared<BencodeDict>(std::move(d));
24
+ #else
25
+ value_ = std::move(d);
26
+ #endif
27
+ }
28
+
29
+ BencodeList& BencodeValue::list_ref() {
30
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
31
+ return *std::get<std::shared_ptr<BencodeList>>(value_);
32
+ #else
33
+ return std::get<BencodeList>(value_);
34
+ #endif
35
+ }
36
+ const BencodeList& BencodeValue::list_ref() const {
37
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
38
+ return *std::get<std::shared_ptr<BencodeList>>(value_);
39
+ #else
40
+ return std::get<BencodeList>(value_);
41
+ #endif
42
+ }
43
+ BencodeDict& BencodeValue::dict_ref() {
44
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
45
+ return *std::get<std::shared_ptr<BencodeDict>>(value_);
46
+ #else
47
+ return std::get<BencodeDict>(value_);
48
+ #endif
49
+ }
50
+ const BencodeDict& BencodeValue::dict_ref() const {
51
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
52
+ return *std::get<std::shared_ptr<BencodeDict>>(value_);
53
+ #else
54
+ return std::get<BencodeDict>(value_);
55
+ #endif
56
+ }
57
+
58
+ // =============================================================================
59
+ // Construction / value semantics
60
+ // =============================================================================
61
+
62
+ BencodeValue::BencodeValue() : type_(Type::String), value_(std::string()) {}
63
+ BencodeValue::BencodeValue(std::int64_t v) : type_(Type::Integer), value_(v) {}
64
+ BencodeValue::BencodeValue(std::string v) : type_(Type::String), value_(std::move(v)) {}
65
+ BencodeValue::BencodeValue(const char* v) : type_(Type::String), value_(std::string(v)) {}
66
+ BencodeValue::BencodeValue(BencodeList v) : type_(Type::List) { set_list(std::move(v)); }
67
+ BencodeValue::BencodeValue(BencodeDict v) : type_(Type::Dictionary) { set_dict(std::move(v)); }
68
+
69
+ BencodeValue::BencodeValue(const BencodeValue& other) : type_(other.type_) {
70
+ // Always a deep copy, regardless of whether containers are boxed.
71
+ switch (type_) {
72
+ case Type::Integer: value_ = std::get<std::int64_t>(other.value_); break;
73
+ case Type::String: value_ = std::get<std::string>(other.value_); break;
74
+ case Type::List: set_list(other.list_ref()); break;
75
+ case Type::Dictionary: set_dict(other.dict_ref()); break;
76
+ }
77
+ }
78
+
79
+ BencodeValue::BencodeValue(BencodeValue&& other) noexcept
80
+ : type_(other.type_), value_(std::move(other.value_)) {}
81
+
82
+ BencodeValue& BencodeValue::operator=(const BencodeValue& other) {
83
+ if (this != &other) {
84
+ BencodeValue tmp(other); // copy-and-swap keeps it exception-safe and simple
85
+ *this = std::move(tmp);
86
+ }
87
+ return *this;
88
+ }
89
+
90
+ BencodeValue& BencodeValue::operator=(BencodeValue&& other) noexcept {
91
+ if (this != &other) {
92
+ type_ = other.type_;
93
+ value_ = std::move(other.value_);
94
+ }
95
+ return *this;
96
+ }
97
+
98
+ BencodeValue::~BencodeValue() = default;
99
+
100
+ // =============================================================================
101
+ // Typed access
102
+ // =============================================================================
103
+
104
+ std::int64_t BencodeValue::as_integer() const {
105
+ if (type_ != Type::Integer) throw std::runtime_error("BencodeValue is not an integer");
106
+ return std::get<std::int64_t>(value_);
107
+ }
108
+
109
+ const std::string& BencodeValue::as_string() const {
110
+ if (type_ != Type::String) throw std::runtime_error("BencodeValue is not a string");
111
+ return std::get<std::string>(value_);
112
+ }
113
+
114
+ const BencodeList& BencodeValue::as_list() const {
115
+ if (type_ != Type::List) throw std::runtime_error("BencodeValue is not a list");
116
+ return list_ref();
117
+ }
118
+
119
+ BencodeList& BencodeValue::as_list() {
120
+ if (type_ != Type::List) throw std::runtime_error("BencodeValue is not a list");
121
+ return list_ref();
122
+ }
123
+
124
+ const BencodeDict& BencodeValue::as_dict() const {
125
+ if (type_ != Type::Dictionary) throw std::runtime_error("BencodeValue is not a dictionary");
126
+ return dict_ref();
127
+ }
128
+
129
+ // =============================================================================
130
+ // Dictionary lookup / building (sorted-vector invariant)
131
+ // =============================================================================
132
+
133
+ namespace {
134
+ // Compare a (key, value) entry against a bare key — used for binary search.
135
+ struct KeyLess {
136
+ bool operator()(const std::pair<std::string, BencodeValue>& e, std::string_view k) const {
137
+ return e.first < k;
138
+ }
139
+ bool operator()(std::string_view k, const std::pair<std::string, BencodeValue>& e) const {
140
+ return k < e.first;
141
+ }
142
+ };
143
+ } // namespace
144
+
145
+ const BencodeValue* BencodeValue::find(std::string_view key) const noexcept {
146
+ if (type_ != Type::Dictionary) return nullptr;
147
+ const BencodeDict& d = dict_ref();
148
+ auto it = std::lower_bound(d.begin(), d.end(), key, KeyLess{});
149
+ if (it != d.end() && it->first == key) return &it->second;
150
+ return nullptr;
151
+ }
152
+
153
+ const BencodeValue& BencodeValue::operator[](std::string_view key) const {
154
+ const BencodeValue* v = find(key);
155
+ if (!v) throw std::runtime_error("Key not found in dictionary: " + std::string(key));
156
+ return *v;
157
+ }
158
+
159
+ BencodeValue& BencodeValue::operator[](std::string_view key) {
160
+ if (type_ != Type::Dictionary) throw std::runtime_error("BencodeValue is not a dictionary");
161
+ BencodeDict& d = dict_ref();
162
+ auto it = std::lower_bound(d.begin(), d.end(), key, KeyLess{});
163
+ if (it != d.end() && it->first == key) return it->second;
164
+ it = d.emplace(it, std::string(key), BencodeValue()); // insert keeps the vector sorted
165
+ return it->second;
166
+ }
167
+
168
+ // =============================================================================
169
+ // List access
170
+ // =============================================================================
171
+
172
+ const BencodeValue& BencodeValue::operator[](std::size_t index) const {
173
+ if (type_ != Type::List) throw std::runtime_error("BencodeValue is not a list");
174
+ const BencodeList& l = list_ref();
175
+ if (index >= l.size()) throw std::runtime_error("Index out of bounds");
176
+ return l[index];
177
+ }
178
+
179
+ BencodeValue& BencodeValue::operator[](std::size_t index) {
180
+ if (type_ != Type::List) throw std::runtime_error("BencodeValue is not a list");
181
+ BencodeList& l = list_ref();
182
+ if (index >= l.size()) throw std::runtime_error("Index out of bounds");
183
+ return l[index];
184
+ }
185
+
186
+ void BencodeValue::push_back(BencodeValue value) {
187
+ if (type_ != Type::List) throw std::runtime_error("BencodeValue is not a list");
188
+ list_ref().push_back(std::move(value));
189
+ }
190
+
191
+ std::size_t BencodeValue::size() const {
192
+ switch (type_) {
193
+ case Type::String: return std::get<std::string>(value_).size();
194
+ case Type::List: return list_ref().size();
195
+ case Type::Dictionary: return dict_ref().size();
196
+ default: throw std::runtime_error("Size not applicable to this type");
197
+ }
198
+ }
199
+
200
+ // =============================================================================
201
+ // Encoding (dictionaries are already sorted → output is canonical)
202
+ // =============================================================================
203
+
204
+ void BencodeValue::encode_to(std::vector<std::uint8_t>& out) const {
205
+ auto append = [&out](const char* s, std::size_t n) {
206
+ out.insert(out.end(), s, s + n);
207
+ };
208
+ auto append_str = [&](const std::string& s) {
209
+ std::string len = std::to_string(s.size());
210
+ append(len.data(), len.size());
211
+ out.push_back(':');
212
+ out.insert(out.end(), s.begin(), s.end());
213
+ };
214
+
215
+ switch (type_) {
216
+ case Type::Integer: {
217
+ std::string s = "i" + std::to_string(std::get<std::int64_t>(value_)) + "e";
218
+ append(s.data(), s.size());
219
+ break;
220
+ }
221
+ case Type::String:
222
+ append_str(std::get<std::string>(value_));
223
+ break;
224
+ case Type::List:
225
+ out.push_back('l');
226
+ for (const BencodeValue& item : list_ref()) item.encode_to(out);
227
+ out.push_back('e');
228
+ break;
229
+ case Type::Dictionary:
230
+ out.push_back('d');
231
+ for (const auto& [key, val] : dict_ref()) { // already sorted, no duplicates
232
+ append_str(key);
233
+ val.encode_to(out);
234
+ }
235
+ out.push_back('e');
236
+ break;
237
+ }
238
+ }
239
+
240
+ std::vector<std::uint8_t> BencodeValue::encode() const {
241
+ std::vector<std::uint8_t> out;
242
+ encode_to(out);
243
+ return out;
244
+ }
245
+
246
+ std::string BencodeValue::encode_string() const {
247
+ std::vector<std::uint8_t> out = encode();
248
+ return std::string(out.begin(), out.end());
249
+ }
250
+
251
+ // =============================================================================
252
+ // Decoding — hardened recursive-descent parser
253
+ // =============================================================================
254
+
255
+ namespace {
256
+
257
+ constexpr int kMaxDepth = 100; // libtorrent's default nesting limit; stops stack-overflow bombs
258
+
259
+ /// Parses one bencode value out of [p, end). All methods advance `p` past what
260
+ /// they consume and return std::nullopt on any malformed input — never throw,
261
+ /// never read out of bounds, never overflow.
262
+ class Parser {
263
+ public:
264
+ Parser(const std::uint8_t* data, const std::uint8_t* end) : p_(data), end_(end) {}
265
+
266
+ std::optional<BencodeValue> parse(int depth) {
267
+ if (depth > kMaxDepth || p_ >= end_) return std::nullopt;
268
+ const std::uint8_t c = *p_;
269
+ if (c == 'i') return parse_integer();
270
+ if (c == 'l') return parse_list(depth);
271
+ if (c == 'd') return parse_dict(depth);
272
+ if (c >= '0' && c <= '9') return parse_string();
273
+ return std::nullopt;
274
+ }
275
+
276
+ const std::uint8_t* cursor() const { return p_; }
277
+
278
+ private:
279
+ bool eof() const { return p_ >= end_; }
280
+
281
+ // Strict canonical integer: optional '-', no leading zeros, no "-0", in
282
+ // int64 range. `term` is the terminating byte ('e' for ints, ':' for strings).
283
+ std::optional<std::int64_t> parse_raw_int(std::uint8_t term) {
284
+ bool negative = false;
285
+ if (!eof() && *p_ == '-') { negative = true; ++p_; }
286
+ if (eof() || *p_ < '0' || *p_ > '9') return std::nullopt; // need at least one digit
287
+
288
+ if (*p_ == '0') { // canonical: a lone zero, never "-0" or "0..."
289
+ ++p_;
290
+ if (negative) return std::nullopt;
291
+ if (eof() || *p_ != term) return std::nullopt;
292
+ ++p_;
293
+ return 0;
294
+ }
295
+
296
+ constexpr std::uint64_t kMaxMag = 9223372036854775808ull; // |INT64_MIN|
297
+ std::uint64_t mag = 0;
298
+ while (!eof() && *p_ >= '0' && *p_ <= '9') {
299
+ const std::uint64_t d = std::uint64_t(*p_ - '0');
300
+ if (mag > (kMaxMag - d) / 10) return std::nullopt; // would exceed int64 range
301
+ mag = mag * 10 + d;
302
+ ++p_;
303
+ }
304
+ if (eof() || *p_ != term) return std::nullopt;
305
+ ++p_;
306
+
307
+ if (negative) {
308
+ if (mag == kMaxMag) return std::numeric_limits<std::int64_t>::min();
309
+ return -std::int64_t(mag);
310
+ }
311
+ if (mag >= kMaxMag) return std::nullopt; // > INT64_MAX
312
+ return std::int64_t(mag);
313
+ }
314
+
315
+ // String length is bounded by the remaining buffer, which both rejects
316
+ // impossible lengths early and keeps the accumulation far from overflow.
317
+ std::optional<std::string> parse_raw_string() {
318
+ if (eof() || *p_ < '0' || *p_ > '9') return std::nullopt;
319
+ const std::uint64_t cap = std::uint64_t(end_ - p_);
320
+ std::uint64_t len = 0;
321
+ while (!eof() && *p_ >= '0' && *p_ <= '9') {
322
+ len = len * 10 + std::uint64_t(*p_ - '0');
323
+ if (len > cap) return std::nullopt; // cannot possibly fit in the buffer
324
+ ++p_;
325
+ }
326
+ if (eof() || *p_ != ':') return std::nullopt;
327
+ ++p_;
328
+ if (std::uint64_t(end_ - p_) < len) return std::nullopt;
329
+ std::string s(reinterpret_cast<const char*>(p_), std::size_t(len));
330
+ p_ += len;
331
+ return s;
332
+ }
333
+
334
+ std::optional<BencodeValue> parse_integer() {
335
+ ++p_; // 'i'
336
+ auto v = parse_raw_int('e');
337
+ if (!v) return std::nullopt;
338
+ return BencodeValue(*v);
339
+ }
340
+
341
+ std::optional<BencodeValue> parse_string() {
342
+ auto s = parse_raw_string();
343
+ if (!s) return std::nullopt;
344
+ return BencodeValue(std::move(*s));
345
+ }
346
+
347
+ std::optional<BencodeValue> parse_list(int depth) {
348
+ ++p_; // 'l'
349
+ BencodeList items;
350
+ while (!eof() && *p_ != 'e') {
351
+ auto v = parse(depth + 1);
352
+ if (!v) return std::nullopt;
353
+ items.push_back(std::move(*v));
354
+ }
355
+ if (eof()) return std::nullopt; // unterminated
356
+ ++p_; // 'e'
357
+ return BencodeValue(std::move(items));
358
+ }
359
+
360
+ std::optional<BencodeValue> parse_dict(int depth) {
361
+ ++p_; // 'd'
362
+ BencodeDict entries;
363
+ while (!eof() && *p_ != 'e') {
364
+ auto key = parse_raw_string();
365
+ if (!key) return std::nullopt;
366
+ auto val = parse(depth + 1);
367
+ if (!val) return std::nullopt;
368
+ entries.emplace_back(std::move(*key), std::move(*val));
369
+ }
370
+ if (eof()) return std::nullopt; // unterminated
371
+ ++p_; // 'e'
372
+
373
+ // Establish the sorted, duplicate-free invariant. We accept any input
374
+ // order (lenient, for interop) but reject genuinely ambiguous duplicate
375
+ // keys. Stable sort preserves first-seen order among would-be dups so the
376
+ // duplicate check below is deterministic.
377
+ std::stable_sort(entries.begin(), entries.end(),
378
+ [](const auto& a, const auto& b) { return a.first < b.first; });
379
+ for (std::size_t i = 1; i < entries.size(); ++i)
380
+ if (entries[i].first == entries[i - 1].first) return std::nullopt;
381
+ return BencodeValue(std::move(entries));
382
+ }
383
+
384
+ const std::uint8_t* p_;
385
+ const std::uint8_t* end_;
386
+ };
387
+
388
+ // Decode exactly one value that must span the whole buffer.
389
+ std::optional<BencodeValue> decode_full(const std::uint8_t* data, std::size_t size) noexcept {
390
+ if (data == nullptr || size == 0) return std::nullopt;
391
+ Parser parser(data, data + size);
392
+ std::optional<BencodeValue> value = parser.parse(0);
393
+ if (!value) return std::nullopt;
394
+ if (parser.cursor() != data + size) return std::nullopt; // trailing garbage
395
+ return value;
396
+ }
397
+
398
+ BencodeValue decode_or_throw(const std::uint8_t* data, std::size_t size) {
399
+ std::optional<BencodeValue> value = decode_full(data, size);
400
+ if (!value) throw std::runtime_error("Invalid bencode data");
401
+ return std::move(*value);
402
+ }
403
+
404
+ } // namespace
405
+
406
+ BencodeValue BencodeDecoder::decode(const std::vector<std::uint8_t>& data) {
407
+ return decode_or_throw(data.data(), data.size());
408
+ }
409
+ BencodeValue BencodeDecoder::decode(const std::string& data) {
410
+ return decode_or_throw(reinterpret_cast<const std::uint8_t*>(data.data()), data.size());
411
+ }
412
+ BencodeValue BencodeDecoder::decode(const std::uint8_t* data, std::size_t size) {
413
+ return decode_or_throw(data, size);
414
+ }
415
+
416
+ namespace bencode {
417
+
418
+ BencodeValue decode(const std::vector<std::uint8_t>& data) {
419
+ return decode_or_throw(data.data(), data.size());
420
+ }
421
+ BencodeValue decode(const std::string& data) {
422
+ return decode_or_throw(reinterpret_cast<const std::uint8_t*>(data.data()), data.size());
423
+ }
424
+
425
+ std::optional<BencodeValue> try_decode(const std::uint8_t* data, std::size_t size) noexcept {
426
+ return decode_full(data, size);
427
+ }
428
+ std::optional<BencodeValue> try_decode(std::string_view data) noexcept {
429
+ return decode_full(reinterpret_cast<const std::uint8_t*>(data.data()), data.size());
430
+ }
431
+
432
+ std::vector<std::uint8_t> encode(const BencodeValue& value) { return value.encode(); }
433
+ std::string encode_string(const BencodeValue& value) { return value.encode_string(); }
434
+
435
+ } // namespace bencode
436
+
437
+ } // namespace librats
@@ -0,0 +1,176 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file bencode.h
5
+ * @brief Bencode value tree, decoder and encoder (BEP 3).
6
+ *
7
+ * Bencode is the serialization format used by every part of BitTorrent and by
8
+ * the DHT's KRPC protocol. This module is shared between both, so it is built
9
+ * unconditionally (not behind RATS_SEARCH_FEATURES).
10
+ *
11
+ * Design:
12
+ * - `BencodeValue` is an owning value tree: an integer, a (binary-safe) string,
13
+ * a list, or a dictionary. The ergonomic accessors make reading parsed data
14
+ * read like the structure itself: `root["info"]["piece length"].as_integer()`.
15
+ * - A dictionary is stored as a *sorted, duplicate-free* vector of key/value
16
+ * pairs. That keeps lookups O(log n) without a per-dict hash allocation, and
17
+ * makes encoding canonical by construction (bencode requires sorted keys).
18
+ * - Decoding is hardened against hostile input: bounded recursion depth,
19
+ * overflow-safe length/integer parsing, strict canonical integers, and a
20
+ * full-buffer-consumption check. Malformed input never crashes — the
21
+ * non-throwing `try_decode` returns `std::nullopt`, the throwing `decode`
22
+ * throws `std::runtime_error`.
23
+ */
24
+
25
+ #include <cstdint>
26
+ #include <optional>
27
+ #include <string>
28
+ #include <string_view>
29
+ #include <utility>
30
+ #include <variant>
31
+ #include <vector>
32
+
33
+ // Some older standard libraries can't place a container of an incomplete type
34
+ // directly inside std::variant (the recursion `BencodeValue` -> container of
35
+ // `BencodeValue`). On those toolchains we box the containers in a shared_ptr.
36
+ // This is fully isolated behind the list_ref()/dict_ref() helpers below, so the
37
+ // rest of the code never sees it. (Deep-copy is implemented explicitly either
38
+ // way, so value semantics are identical on both paths.)
39
+ #ifndef LIBRATS_BENCODE_BOXED_CONTAINERS
40
+ # if defined(__GNUC__) && (__GNUC__ <= 11)
41
+ # define LIBRATS_BENCODE_BOXED_CONTAINERS 1
42
+ # else
43
+ # define LIBRATS_BENCODE_BOXED_CONTAINERS 0
44
+ # endif
45
+ #endif
46
+
47
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
48
+ #include <memory>
49
+ #endif
50
+
51
+ namespace librats {
52
+
53
+ class BencodeValue;
54
+
55
+ /// A bencode list is a plain vector of values.
56
+ using BencodeList = std::vector<BencodeValue>;
57
+
58
+ /// A bencode dictionary, stored sorted by key with no duplicates. Keys are
59
+ /// byte strings (binary-safe). The sorted invariant is maintained by both the
60
+ /// decoder and the mutable `operator[]`, so iteration and encoding are canonical.
61
+ using BencodeDict = std::vector<std::pair<std::string, BencodeValue>>;
62
+
63
+ /**
64
+ * @brief One bencode value: integer, string, list or dictionary.
65
+ *
66
+ * Copying is a deep copy (true value semantics). Construct leaves directly
67
+ * (`BencodeValue(42)`, `BencodeValue("x")`) or containers via `create_list()` /
68
+ * `create_dict()` and the mutable accessors.
69
+ */
70
+ class BencodeValue {
71
+ public:
72
+ enum class Type { Integer, String, List, Dictionary };
73
+
74
+ BencodeValue(); ///< empty string (binary-safe, zero length)
75
+ BencodeValue(std::int64_t value);
76
+ BencodeValue(std::string value);
77
+ BencodeValue(const char* value);
78
+ BencodeValue(BencodeList value);
79
+ BencodeValue(BencodeDict value);
80
+
81
+ BencodeValue(const BencodeValue& other);
82
+ BencodeValue(BencodeValue&& other) noexcept;
83
+ BencodeValue& operator=(const BencodeValue& other);
84
+ BencodeValue& operator=(BencodeValue&& other) noexcept;
85
+ ~BencodeValue();
86
+
87
+ // ---- type ----
88
+ Type type() const noexcept { return type_; }
89
+ Type get_type() const noexcept { return type_; } ///< alias
90
+ bool is_integer() const noexcept { return type_ == Type::Integer; }
91
+ bool is_string() const noexcept { return type_ == Type::String; }
92
+ bool is_list() const noexcept { return type_ == Type::List; }
93
+ bool is_dict() const noexcept { return type_ == Type::Dictionary; }
94
+
95
+ // ---- typed access (throw std::runtime_error on a type mismatch) ----
96
+ std::int64_t as_integer() const;
97
+ const std::string& as_string() const;
98
+ const BencodeList& as_list() const;
99
+ const BencodeDict& as_dict() const;
100
+ BencodeList& as_list(); ///< mutable list (lists carry no invariant)
101
+
102
+ // ---- safe, non-throwing helpers ----
103
+ /// Dictionary lookup. Returns nullptr if this is not a dict or the key is
104
+ /// absent. Never throws — the preferred way to read untrusted input.
105
+ const BencodeValue* find(std::string_view key) const noexcept;
106
+ bool has_key(std::string_view key) const noexcept { return find(key) != nullptr; }
107
+
108
+ // ---- dictionary building / reading ----
109
+ /// Const dictionary read; throws std::runtime_error if the key is missing.
110
+ const BencodeValue& operator[](std::string_view key) const;
111
+ /// Mutable dictionary access; inserts a default-constructed value (keeping
112
+ /// the sorted invariant) if the key is absent. Throws if this is not a dict.
113
+ BencodeValue& operator[](std::string_view key);
114
+
115
+ // ---- list building / reading ----
116
+ const BencodeValue& operator[](std::size_t index) const; ///< throws if out of range
117
+ BencodeValue& operator[](std::size_t index); ///< throws if out of range
118
+ void push_back(BencodeValue value); ///< append to a list
119
+ std::size_t size() const; ///< element/byte count for string/list/dict; throws otherwise
120
+
121
+ // ---- encoding ----
122
+ std::vector<std::uint8_t> encode() const;
123
+ std::string encode_string() const;
124
+ void encode_to(std::vector<std::uint8_t>& out) const;
125
+
126
+ // ---- factories (kept for readability at call sites) ----
127
+ static BencodeValue create_integer(std::int64_t v) { return BencodeValue(v); }
128
+ static BencodeValue create_string(std::string v) { return BencodeValue(std::move(v)); }
129
+ static BencodeValue create_list() { return BencodeValue(BencodeList{}); }
130
+ static BencodeValue create_dict() { return BencodeValue(BencodeDict{}); }
131
+
132
+ private:
133
+ Type type_;
134
+ #if LIBRATS_BENCODE_BOXED_CONTAINERS
135
+ std::variant<std::int64_t, std::string,
136
+ std::shared_ptr<BencodeList>, std::shared_ptr<BencodeDict>> value_;
137
+ #else
138
+ std::variant<std::int64_t, std::string, BencodeList, BencodeDict> value_;
139
+ #endif
140
+
141
+ // The only place that knows about container boxing.
142
+ void set_list(BencodeList l);
143
+ void set_dict(BencodeDict d);
144
+ BencodeList& list_ref();
145
+ const BencodeList& list_ref() const;
146
+ BencodeDict& dict_ref();
147
+ const BencodeDict& dict_ref() const;
148
+ };
149
+
150
+ /**
151
+ * @brief Bencode decoder entry points (throwing — kept for existing callers).
152
+ *
153
+ * Each decodes exactly one value and requires it to span the whole buffer.
154
+ * Throws std::runtime_error on any malformed input.
155
+ */
156
+ class BencodeDecoder {
157
+ public:
158
+ static BencodeValue decode(const std::vector<std::uint8_t>& data);
159
+ static BencodeValue decode(const std::string& data);
160
+ static BencodeValue decode(const std::uint8_t* data, std::size_t size);
161
+ };
162
+
163
+ namespace bencode {
164
+ /// Throwing decode (one value, whole buffer). Throws std::runtime_error.
165
+ BencodeValue decode(const std::vector<std::uint8_t>& data);
166
+ BencodeValue decode(const std::string& data);
167
+
168
+ /// Non-throwing decode (one value, whole buffer). nullopt on malformed input.
169
+ std::optional<BencodeValue> try_decode(const std::uint8_t* data, std::size_t size) noexcept;
170
+ std::optional<BencodeValue> try_decode(std::string_view data) noexcept;
171
+
172
+ std::vector<std::uint8_t> encode(const BencodeValue& value);
173
+ std::string encode_string(const BencodeValue& value);
174
+ }
175
+
176
+ } // namespace librats