├── .clang-format ├── .github └── workflows │ └── greetings.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md └── src ├── anime.h ├── colors.h ├── common.c ├── common.h ├── input.c ├── input.h ├── main.c ├── parser ├── json.c ├── json.h ├── regex.c └── regex.h ├── provider.c ├── provider.h ├── sites ├── animepahe.c ├── animepahe.h ├── base.h ├── gogoanime.c ├── gogoanime.h └── sites.h ├── utils.c ├── utils.h ├── web_client.c └── web_client.h /.clang-format: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # clang-format configuration file. Intended for clang-format >= 4. 4 | # 5 | # For more information, see: 6 | # 7 | # Documentation/process/clang-format.rst 8 | # https://clang.llvm.org/docs/ClangFormat.html 9 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 10 | # 11 | --- 12 | AccessModifierOffset: -4 13 | AlignAfterOpenBracket: Align 14 | AlignConsecutiveAssignments: false 15 | AlignConsecutiveDeclarations: false 16 | #AlignEscapedNewlines: Left # Unknown to clang-format-4.0 17 | AlignOperands: true 18 | AlignTrailingComments: false 19 | AllowAllParametersOfDeclarationOnNextLine: false 20 | AllowShortBlocksOnASingleLine: false 21 | AllowShortCaseLabelsOnASingleLine: false 22 | AllowShortFunctionsOnASingleLine: None 23 | AllowShortIfStatementsOnASingleLine: false 24 | AllowShortLoopsOnASingleLine: false 25 | AlwaysBreakAfterDefinitionReturnType: None 26 | AlwaysBreakAfterReturnType: None 27 | AlwaysBreakBeforeMultilineStrings: false 28 | AlwaysBreakTemplateDeclarations: false 29 | BinPackArguments: true 30 | BinPackParameters: true 31 | BraceWrapping: 32 | AfterClass: false 33 | AfterControlStatement: false 34 | AfterEnum: false 35 | AfterFunction: true 36 | AfterNamespace: true 37 | AfterObjCDeclaration: false 38 | AfterStruct: false 39 | AfterUnion: false 40 | #AfterExternBlock: false # Unknown to clang-format-5.0 41 | BeforeCatch: false 42 | BeforeElse: false 43 | IndentBraces: false 44 | #SplitEmptyFunction: true # Unknown to clang-format-4.0 45 | #SplitEmptyRecord: true # Unknown to clang-format-4.0 46 | #SplitEmptyNamespace: true # Unknown to clang-format-4.0 47 | BreakBeforeBinaryOperators: None 48 | BreakBeforeBraces: Custom 49 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 50 | BreakBeforeTernaryOperators: false 51 | BreakConstructorInitializersBeforeComma: false 52 | #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 53 | BreakAfterJavaFieldAnnotations: false 54 | BreakStringLiterals: false 55 | ColumnLimit: 80 56 | CommentPragmas: '^ IWYU pragma:' 57 | #CompactNamespaces: false # Unknown to clang-format-4.0 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 59 | ConstructorInitializerIndentWidth: 4 60 | ContinuationIndentWidth: 4 61 | Cpp11BracedListStyle: false 62 | DerivePointerAlignment: false 63 | DisableFormat: false 64 | ExperimentalAutoDetectBinPacking: false 65 | #FixNamespaceComments: false # Unknown to clang-format-4.0 66 | 67 | # Taken from: 68 | # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ 69 | # | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ 70 | # | sort | uniq 71 | ForEachMacros: 72 | - 'apei_estatus_for_each_section' 73 | - 'ata_for_each_dev' 74 | - 'ata_for_each_link' 75 | - '__ata_qc_for_each' 76 | - 'ata_qc_for_each' 77 | - 'ata_qc_for_each_raw' 78 | - 'ata_qc_for_each_with_internal' 79 | - 'ax25_for_each' 80 | - 'ax25_uid_for_each' 81 | - '__bio_for_each_bvec' 82 | - 'bio_for_each_bvec' 83 | - 'bio_for_each_bvec_all' 84 | - 'bio_for_each_integrity_vec' 85 | - '__bio_for_each_segment' 86 | - 'bio_for_each_segment' 87 | - 'bio_for_each_segment_all' 88 | - 'bio_list_for_each' 89 | - 'bip_for_each_vec' 90 | - 'bitmap_for_each_clear_region' 91 | - 'bitmap_for_each_set_region' 92 | - 'blkg_for_each_descendant_post' 93 | - 'blkg_for_each_descendant_pre' 94 | - 'blk_queue_for_each_rl' 95 | - 'bond_for_each_slave' 96 | - 'bond_for_each_slave_rcu' 97 | - 'bpf_for_each_spilled_reg' 98 | - 'btree_for_each_safe128' 99 | - 'btree_for_each_safe32' 100 | - 'btree_for_each_safe64' 101 | - 'btree_for_each_safel' 102 | - 'card_for_each_dev' 103 | - 'cgroup_taskset_for_each' 104 | - 'cgroup_taskset_for_each_leader' 105 | - 'cpufreq_for_each_entry' 106 | - 'cpufreq_for_each_entry_idx' 107 | - 'cpufreq_for_each_valid_entry' 108 | - 'cpufreq_for_each_valid_entry_idx' 109 | - 'css_for_each_child' 110 | - 'css_for_each_descendant_post' 111 | - 'css_for_each_descendant_pre' 112 | - 'device_for_each_child_node' 113 | - 'displayid_iter_for_each' 114 | - 'dma_fence_chain_for_each' 115 | - 'do_for_each_ftrace_op' 116 | - 'drm_atomic_crtc_for_each_plane' 117 | - 'drm_atomic_crtc_state_for_each_plane' 118 | - 'drm_atomic_crtc_state_for_each_plane_state' 119 | - 'drm_atomic_for_each_plane_damage' 120 | - 'drm_client_for_each_connector_iter' 121 | - 'drm_client_for_each_modeset' 122 | - 'drm_connector_for_each_possible_encoder' 123 | - 'drm_for_each_bridge_in_chain' 124 | - 'drm_for_each_connector_iter' 125 | - 'drm_for_each_crtc' 126 | - 'drm_for_each_crtc_reverse' 127 | - 'drm_for_each_encoder' 128 | - 'drm_for_each_encoder_mask' 129 | - 'drm_for_each_fb' 130 | - 'drm_for_each_legacy_plane' 131 | - 'drm_for_each_plane' 132 | - 'drm_for_each_plane_mask' 133 | - 'drm_for_each_privobj' 134 | - 'drm_mm_for_each_hole' 135 | - 'drm_mm_for_each_node' 136 | - 'drm_mm_for_each_node_in_range' 137 | - 'drm_mm_for_each_node_safe' 138 | - 'flow_action_for_each' 139 | - 'for_each_acpi_dev_match' 140 | - 'for_each_active_dev_scope' 141 | - 'for_each_active_drhd_unit' 142 | - 'for_each_active_iommu' 143 | - 'for_each_aggr_pgid' 144 | - 'for_each_available_child_of_node' 145 | - 'for_each_bio' 146 | - 'for_each_board_func_rsrc' 147 | - 'for_each_bvec' 148 | - 'for_each_card_auxs' 149 | - 'for_each_card_auxs_safe' 150 | - 'for_each_card_components' 151 | - 'for_each_card_dapms' 152 | - 'for_each_card_pre_auxs' 153 | - 'for_each_card_prelinks' 154 | - 'for_each_card_rtds' 155 | - 'for_each_card_rtds_safe' 156 | - 'for_each_card_widgets' 157 | - 'for_each_card_widgets_safe' 158 | - 'for_each_cgroup_storage_type' 159 | - 'for_each_child_of_node' 160 | - 'for_each_clear_bit' 161 | - 'for_each_clear_bit_from' 162 | - 'for_each_cmsghdr' 163 | - 'for_each_compatible_node' 164 | - 'for_each_component_dais' 165 | - 'for_each_component_dais_safe' 166 | - 'for_each_comp_order' 167 | - 'for_each_console' 168 | - 'for_each_cpu' 169 | - 'for_each_cpu_and' 170 | - 'for_each_cpu_not' 171 | - 'for_each_cpu_wrap' 172 | - 'for_each_dapm_widgets' 173 | - 'for_each_dev_addr' 174 | - 'for_each_dev_scope' 175 | - 'for_each_dma_cap_mask' 176 | - 'for_each_dpcm_be' 177 | - 'for_each_dpcm_be_rollback' 178 | - 'for_each_dpcm_be_safe' 179 | - 'for_each_dpcm_fe' 180 | - 'for_each_drhd_unit' 181 | - 'for_each_dss_dev' 182 | - 'for_each_dtpm_table' 183 | - 'for_each_efi_memory_desc' 184 | - 'for_each_efi_memory_desc_in_map' 185 | - 'for_each_element' 186 | - 'for_each_element_extid' 187 | - 'for_each_element_id' 188 | - 'for_each_endpoint_of_node' 189 | - 'for_each_evictable_lru' 190 | - 'for_each_fib6_node_rt_rcu' 191 | - 'for_each_fib6_walker_rt' 192 | - 'for_each_free_mem_pfn_range_in_zone' 193 | - 'for_each_free_mem_pfn_range_in_zone_from' 194 | - 'for_each_free_mem_range' 195 | - 'for_each_free_mem_range_reverse' 196 | - 'for_each_func_rsrc' 197 | - 'for_each_hstate' 198 | - 'for_each_if' 199 | - 'for_each_iommu' 200 | - 'for_each_ip_tunnel_rcu' 201 | - 'for_each_irq_nr' 202 | - 'for_each_link_codecs' 203 | - 'for_each_link_cpus' 204 | - 'for_each_link_platforms' 205 | - 'for_each_lru' 206 | - 'for_each_matching_node' 207 | - 'for_each_matching_node_and_match' 208 | - 'for_each_member' 209 | - 'for_each_memcg_cache_index' 210 | - 'for_each_mem_pfn_range' 211 | - '__for_each_mem_range' 212 | - 'for_each_mem_range' 213 | - '__for_each_mem_range_rev' 214 | - 'for_each_mem_range_rev' 215 | - 'for_each_mem_region' 216 | - 'for_each_migratetype_order' 217 | - 'for_each_msi_entry' 218 | - 'for_each_msi_entry_safe' 219 | - 'for_each_msi_vector' 220 | - 'for_each_net' 221 | - 'for_each_net_continue_reverse' 222 | - 'for_each_netdev' 223 | - 'for_each_netdev_continue' 224 | - 'for_each_netdev_continue_rcu' 225 | - 'for_each_netdev_continue_reverse' 226 | - 'for_each_netdev_feature' 227 | - 'for_each_netdev_in_bond_rcu' 228 | - 'for_each_netdev_rcu' 229 | - 'for_each_netdev_reverse' 230 | - 'for_each_netdev_safe' 231 | - 'for_each_net_rcu' 232 | - 'for_each_new_connector_in_state' 233 | - 'for_each_new_crtc_in_state' 234 | - 'for_each_new_mst_mgr_in_state' 235 | - 'for_each_new_plane_in_state' 236 | - 'for_each_new_private_obj_in_state' 237 | - 'for_each_node' 238 | - 'for_each_node_by_name' 239 | - 'for_each_node_by_type' 240 | - 'for_each_node_mask' 241 | - 'for_each_node_state' 242 | - 'for_each_node_with_cpus' 243 | - 'for_each_node_with_property' 244 | - 'for_each_nonreserved_multicast_dest_pgid' 245 | - 'for_each_of_allnodes' 246 | - 'for_each_of_allnodes_from' 247 | - 'for_each_of_cpu_node' 248 | - 'for_each_of_pci_range' 249 | - 'for_each_old_connector_in_state' 250 | - 'for_each_old_crtc_in_state' 251 | - 'for_each_old_mst_mgr_in_state' 252 | - 'for_each_oldnew_connector_in_state' 253 | - 'for_each_oldnew_crtc_in_state' 254 | - 'for_each_oldnew_mst_mgr_in_state' 255 | - 'for_each_oldnew_plane_in_state' 256 | - 'for_each_oldnew_plane_in_state_reverse' 257 | - 'for_each_oldnew_private_obj_in_state' 258 | - 'for_each_old_plane_in_state' 259 | - 'for_each_old_private_obj_in_state' 260 | - 'for_each_online_cpu' 261 | - 'for_each_online_node' 262 | - 'for_each_online_pgdat' 263 | - 'for_each_pci_bridge' 264 | - 'for_each_pci_dev' 265 | - 'for_each_pci_msi_entry' 266 | - 'for_each_pcm_streams' 267 | - 'for_each_physmem_range' 268 | - 'for_each_populated_zone' 269 | - 'for_each_possible_cpu' 270 | - 'for_each_present_cpu' 271 | - 'for_each_prime_number' 272 | - 'for_each_prime_number_from' 273 | - 'for_each_process' 274 | - 'for_each_process_thread' 275 | - 'for_each_prop_codec_conf' 276 | - 'for_each_prop_dai_codec' 277 | - 'for_each_prop_dai_cpu' 278 | - 'for_each_prop_dlc_codecs' 279 | - 'for_each_prop_dlc_cpus' 280 | - 'for_each_prop_dlc_platforms' 281 | - 'for_each_property_of_node' 282 | - 'for_each_registered_fb' 283 | - 'for_each_requested_gpio' 284 | - 'for_each_requested_gpio_in_range' 285 | - 'for_each_reserved_mem_range' 286 | - 'for_each_reserved_mem_region' 287 | - 'for_each_rtd_codec_dais' 288 | - 'for_each_rtd_components' 289 | - 'for_each_rtd_cpu_dais' 290 | - 'for_each_rtd_dais' 291 | - 'for_each_set_bit' 292 | - 'for_each_set_bit_from' 293 | - 'for_each_set_clump8' 294 | - 'for_each_sg' 295 | - 'for_each_sg_dma_page' 296 | - 'for_each_sg_page' 297 | - 'for_each_sgtable_dma_page' 298 | - 'for_each_sgtable_dma_sg' 299 | - 'for_each_sgtable_page' 300 | - 'for_each_sgtable_sg' 301 | - 'for_each_sibling_event' 302 | - 'for_each_subelement' 303 | - 'for_each_subelement_extid' 304 | - 'for_each_subelement_id' 305 | - '__for_each_thread' 306 | - 'for_each_thread' 307 | - 'for_each_unicast_dest_pgid' 308 | - 'for_each_vsi' 309 | - 'for_each_wakeup_source' 310 | - 'for_each_zone' 311 | - 'for_each_zone_zonelist' 312 | - 'for_each_zone_zonelist_nodemask' 313 | - 'fwnode_for_each_available_child_node' 314 | - 'fwnode_for_each_child_node' 315 | - 'fwnode_graph_for_each_endpoint' 316 | - 'gadget_for_each_ep' 317 | - 'genradix_for_each' 318 | - 'genradix_for_each_from' 319 | - 'hash_for_each' 320 | - 'hash_for_each_possible' 321 | - 'hash_for_each_possible_rcu' 322 | - 'hash_for_each_possible_rcu_notrace' 323 | - 'hash_for_each_possible_safe' 324 | - 'hash_for_each_rcu' 325 | - 'hash_for_each_safe' 326 | - 'hctx_for_each_ctx' 327 | - 'hlist_bl_for_each_entry' 328 | - 'hlist_bl_for_each_entry_rcu' 329 | - 'hlist_bl_for_each_entry_safe' 330 | - 'hlist_for_each' 331 | - 'hlist_for_each_entry' 332 | - 'hlist_for_each_entry_continue' 333 | - 'hlist_for_each_entry_continue_rcu' 334 | - 'hlist_for_each_entry_continue_rcu_bh' 335 | - 'hlist_for_each_entry_from' 336 | - 'hlist_for_each_entry_from_rcu' 337 | - 'hlist_for_each_entry_rcu' 338 | - 'hlist_for_each_entry_rcu_bh' 339 | - 'hlist_for_each_entry_rcu_notrace' 340 | - 'hlist_for_each_entry_safe' 341 | - 'hlist_for_each_entry_srcu' 342 | - '__hlist_for_each_rcu' 343 | - 'hlist_for_each_safe' 344 | - 'hlist_nulls_for_each_entry' 345 | - 'hlist_nulls_for_each_entry_from' 346 | - 'hlist_nulls_for_each_entry_rcu' 347 | - 'hlist_nulls_for_each_entry_safe' 348 | - 'i3c_bus_for_each_i2cdev' 349 | - 'i3c_bus_for_each_i3cdev' 350 | - 'ide_host_for_each_port' 351 | - 'ide_port_for_each_dev' 352 | - 'ide_port_for_each_present_dev' 353 | - 'idr_for_each_entry' 354 | - 'idr_for_each_entry_continue' 355 | - 'idr_for_each_entry_continue_ul' 356 | - 'idr_for_each_entry_ul' 357 | - 'in_dev_for_each_ifa_rcu' 358 | - 'in_dev_for_each_ifa_rtnl' 359 | - 'inet_bind_bucket_for_each' 360 | - 'inet_lhash2_for_each_icsk_rcu' 361 | - 'key_for_each' 362 | - 'key_for_each_safe' 363 | - 'klp_for_each_func' 364 | - 'klp_for_each_func_safe' 365 | - 'klp_for_each_func_static' 366 | - 'klp_for_each_object' 367 | - 'klp_for_each_object_safe' 368 | - 'klp_for_each_object_static' 369 | - 'kunit_suite_for_each_test_case' 370 | - 'kvm_for_each_memslot' 371 | - 'kvm_for_each_vcpu' 372 | - 'list_for_each' 373 | - 'list_for_each_codec' 374 | - 'list_for_each_codec_safe' 375 | - 'list_for_each_continue' 376 | - 'list_for_each_entry' 377 | - 'list_for_each_entry_continue' 378 | - 'list_for_each_entry_continue_rcu' 379 | - 'list_for_each_entry_continue_reverse' 380 | - 'list_for_each_entry_from' 381 | - 'list_for_each_entry_from_rcu' 382 | - 'list_for_each_entry_from_reverse' 383 | - 'list_for_each_entry_lockless' 384 | - 'list_for_each_entry_rcu' 385 | - 'list_for_each_entry_reverse' 386 | - 'list_for_each_entry_safe' 387 | - 'list_for_each_entry_safe_continue' 388 | - 'list_for_each_entry_safe_from' 389 | - 'list_for_each_entry_safe_reverse' 390 | - 'list_for_each_entry_srcu' 391 | - 'list_for_each_prev' 392 | - 'list_for_each_prev_safe' 393 | - 'list_for_each_safe' 394 | - 'llist_for_each' 395 | - 'llist_for_each_entry' 396 | - 'llist_for_each_entry_safe' 397 | - 'llist_for_each_safe' 398 | - 'mci_for_each_dimm' 399 | - 'media_device_for_each_entity' 400 | - 'media_device_for_each_intf' 401 | - 'media_device_for_each_link' 402 | - 'media_device_for_each_pad' 403 | - 'nanddev_io_for_each_page' 404 | - 'netdev_for_each_lower_dev' 405 | - 'netdev_for_each_lower_private' 406 | - 'netdev_for_each_lower_private_rcu' 407 | - 'netdev_for_each_mc_addr' 408 | - 'netdev_for_each_uc_addr' 409 | - 'netdev_for_each_upper_dev_rcu' 410 | - 'netdev_hw_addr_list_for_each' 411 | - 'nft_rule_for_each_expr' 412 | - 'nla_for_each_attr' 413 | - 'nla_for_each_nested' 414 | - 'nlmsg_for_each_attr' 415 | - 'nlmsg_for_each_msg' 416 | - 'nr_neigh_for_each' 417 | - 'nr_neigh_for_each_safe' 418 | - 'nr_node_for_each' 419 | - 'nr_node_for_each_safe' 420 | - 'of_for_each_phandle' 421 | - 'of_property_for_each_string' 422 | - 'of_property_for_each_u32' 423 | - 'pci_bus_for_each_resource' 424 | - 'pcl_for_each_chunk' 425 | - 'pcl_for_each_segment' 426 | - 'pcm_for_each_format' 427 | - 'ping_portaddr_for_each_entry' 428 | - 'plist_for_each' 429 | - 'plist_for_each_continue' 430 | - 'plist_for_each_entry' 431 | - 'plist_for_each_entry_continue' 432 | - 'plist_for_each_entry_safe' 433 | - 'plist_for_each_safe' 434 | - 'pnp_for_each_card' 435 | - 'pnp_for_each_dev' 436 | - 'protocol_for_each_card' 437 | - 'protocol_for_each_dev' 438 | - 'queue_for_each_hw_ctx' 439 | - 'radix_tree_for_each_slot' 440 | - 'radix_tree_for_each_tagged' 441 | - 'rb_for_each' 442 | - 'rbtree_postorder_for_each_entry_safe' 443 | - 'rdma_for_each_block' 444 | - 'rdma_for_each_port' 445 | - 'rdma_umem_for_each_dma_block' 446 | - 'resource_list_for_each_entry' 447 | - 'resource_list_for_each_entry_safe' 448 | - 'rhl_for_each_entry_rcu' 449 | - 'rhl_for_each_rcu' 450 | - 'rht_for_each' 451 | - 'rht_for_each_entry' 452 | - 'rht_for_each_entry_from' 453 | - 'rht_for_each_entry_rcu' 454 | - 'rht_for_each_entry_rcu_from' 455 | - 'rht_for_each_entry_safe' 456 | - 'rht_for_each_from' 457 | - 'rht_for_each_rcu' 458 | - 'rht_for_each_rcu_from' 459 | - '__rq_for_each_bio' 460 | - 'rq_for_each_bvec' 461 | - 'rq_for_each_segment' 462 | - 'scsi_for_each_prot_sg' 463 | - 'scsi_for_each_sg' 464 | - 'sctp_for_each_hentry' 465 | - 'sctp_skb_for_each' 466 | - 'shdma_for_each_chan' 467 | - '__shost_for_each_device' 468 | - 'shost_for_each_device' 469 | - 'sk_for_each' 470 | - 'sk_for_each_bound' 471 | - 'sk_for_each_entry_offset_rcu' 472 | - 'sk_for_each_from' 473 | - 'sk_for_each_rcu' 474 | - 'sk_for_each_safe' 475 | - 'sk_nulls_for_each' 476 | - 'sk_nulls_for_each_from' 477 | - 'sk_nulls_for_each_rcu' 478 | - 'snd_array_for_each' 479 | - 'snd_pcm_group_for_each_entry' 480 | - 'snd_soc_dapm_widget_for_each_path' 481 | - 'snd_soc_dapm_widget_for_each_path_safe' 482 | - 'snd_soc_dapm_widget_for_each_sink_path' 483 | - 'snd_soc_dapm_widget_for_each_source_path' 484 | - 'tb_property_for_each' 485 | - 'tcf_exts_for_each_action' 486 | - 'udp_portaddr_for_each_entry' 487 | - 'udp_portaddr_for_each_entry_rcu' 488 | - 'usb_hub_for_each_child' 489 | - 'v4l2_device_for_each_subdev' 490 | - 'v4l2_m2m_for_each_dst_buf' 491 | - 'v4l2_m2m_for_each_dst_buf_safe' 492 | - 'v4l2_m2m_for_each_src_buf' 493 | - 'v4l2_m2m_for_each_src_buf_safe' 494 | - 'virtio_device_for_each_vq' 495 | - 'while_for_each_ftrace_op' 496 | - 'xa_for_each' 497 | - 'xa_for_each_marked' 498 | - 'xa_for_each_range' 499 | - 'xa_for_each_start' 500 | - 'xas_for_each' 501 | - 'xas_for_each_conflict' 502 | - 'xas_for_each_marked' 503 | - 'xbc_array_for_each_value' 504 | - 'xbc_for_each_key_value' 505 | - 'xbc_node_for_each_array_value' 506 | - 'xbc_node_for_each_child' 507 | - 'xbc_node_for_each_key_value' 508 | - 'zorro_for_each_dev' 509 | 510 | #IncludeBlocks: Preserve # Unknown to clang-format-5.0 511 | IncludeCategories: 512 | - Regex: '.*' 513 | Priority: 1 514 | IncludeIsMainRegex: '(Test)?$' 515 | IndentCaseLabels: false 516 | #IndentPPDirectives: None # Unknown to clang-format-5.0 517 | IndentWidth: 4 518 | IndentWrappedFunctionNames: false 519 | JavaScriptQuotes: Leave 520 | JavaScriptWrapImports: true 521 | KeepEmptyLinesAtTheStartOfBlocks: false 522 | MacroBlockBegin: '' 523 | MacroBlockEnd: '' 524 | MaxEmptyLinesToKeep: 1 525 | NamespaceIndentation: None 526 | #ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 527 | ObjCBlockIndentWidth: 4 528 | ObjCSpaceAfterProperty: true 529 | ObjCSpaceBeforeProtocolList: true 530 | 531 | # Taken from git's rules 532 | #PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 533 | PenaltyBreakBeforeFirstCallParameter: 30 534 | PenaltyBreakComment: 10 535 | PenaltyBreakFirstLessLess: 0 536 | PenaltyBreakString: 10 537 | PenaltyExcessCharacter: 100 538 | PenaltyReturnTypeOnItsOwnLine: 60 539 | 540 | PointerAlignment: Right 541 | ReflowComments: false 542 | SortIncludes: false 543 | #SortUsingDeclarations: false # Unknown to clang-format-4.0 544 | SpaceAfterCStyleCast: false 545 | SpaceAfterTemplateKeyword: true 546 | SpaceBeforeAssignmentOperators: true 547 | #SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 548 | #SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 549 | SpaceBeforeParens: ControlStatements 550 | #SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 551 | SpaceInEmptyParentheses: false 552 | SpacesBeforeTrailingComments: 1 553 | SpacesInAngles: false 554 | SpacesInContainerLiterals: false 555 | SpacesInCStyleCastParentheses: false 556 | SpacesInParentheses: false 557 | SpacesInSquareBrackets: false 558 | Standard: Cpp03 559 | TabWidth: 4 560 | UseTab: Never 561 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | steps: 12 | - uses: actions/first-interaction@v1 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | issue-message: 'Message that will be displayed on users first issue' 16 | pr-message: 'Message that will be displayed on users first pull request' 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | canime 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | 3 | # includes and libs 4 | CFLAGS = $(INCS) -D_POSIX_C_SOURCE=200809L 5 | LDFLAGS = -lcurl 6 | 7 | # paths 8 | OBJ_DIR = obj 9 | DEST_DIR = /usr/local 10 | 11 | BIN = canime 12 | SRC = $(wildcard src/*.c) $(wildcard src/**/*.c) 13 | OBJ = $(patsubst src/%.c,obj/%.o,$(SRC)) 14 | 15 | all: options $(BIN) 16 | 17 | options: 18 | @echo canime build options: 19 | @echo "CFLAGS = $(CFLAGS)" 20 | @echo "LDFLAGS = $(LDFLAGS)" 21 | @echo "CC = $(CC)" 22 | 23 | $(BIN): $(OBJ) 24 | $(CC) -o $(BIN) $(OBJ) $(LDFLAGS) 25 | 26 | $(OBJ_DIR)/%.o: src/%.c 27 | @mkdir -p $(dir $@) 28 | $(CC) $(CFLAGS) -o $@ -c $< 29 | 30 | clean: 31 | $(RM) -rf $(OBJ_DIR) $(BIN) 32 | 33 | install: $(BIN) 34 | mkdir -p $(DEST_DIR)/bin 35 | cp -f $(BIN) $(DEST_DIR)/bin 36 | chmod 755 $(DEST_DIR)/bin/$(BIN) 37 | 38 | uninstall: 39 | rm -f $(DEST_DIR)/bin/$(BIN) 40 | 41 | .PHONY: all options clean install uninstall 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

canime

3 |

Port of ani-cli with more features 😉

4 |
5 | 6 | ## WIP 7 | Stay tuned, more features coming soon! 8 | 9 | ## Installation 10 | ```Console 11 | $ git clone https://github.com/Dink4n/canime.git 12 | $ cd canime 13 | $ sudo make clean install 14 | 15 | ``` 16 | 17 | ## Dependencies 18 | * mpv 19 | * curl 20 | 21 | ## TODO 22 | - [ ] parallel downloading 23 | - [ ] video quality selection 24 | - [ ] more providers! 25 | 26 | ## Credits 27 | [ani-cli](https://github.com/pystardust/ani-cli) 28 | -------------------------------------------------------------------------------- /src/anime.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_ANIME_H 2 | #define CANIME_ANIME_H 3 | 4 | #include "web_client.h" 5 | 6 | #define MAX_ANIME_NAME_LEN 128 7 | #define MAX_ANIME_SEARCH_RESULTS 10 8 | 9 | struct Episode { 10 | char url[URL_BUF_SIZE]; 11 | char referer[URL_BUF_SIZE]; 12 | }; 13 | 14 | struct AnimeInfo { 15 | char *title; 16 | unsigned int current_episode; 17 | unsigned int total_episodes; 18 | struct Episode episode; 19 | }; 20 | 21 | struct SearchResults { 22 | unsigned int total; 23 | char results[MAX_ANIME_SEARCH_RESULTS][MAX_ANIME_NAME_LEN]; 24 | 25 | // Addtional metadata 26 | void *metadata; 27 | }; 28 | 29 | #endif /* CANIME_ANIME_H */ 30 | -------------------------------------------------------------------------------- /src/colors.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_COLORS_H 2 | #define CANIME_COLORS_H 3 | 4 | /* 5 | * This is free and unencumbered software released into the public domain. 6 | * 7 | * For more information, please refer to 8 | */ 9 | 10 | //Regular text 11 | #define C_BLK "\x1B[0;30m" 12 | #define C_RED "\x1B[0;31m" 13 | #define C_GRN "\x1B[0;32m" 14 | #define C_YEL "\x1B[0;33m" 15 | #define C_BLU "\x1B[0;34m" 16 | #define C_MAG "\x1B[0;35m" 17 | #define C_CYN "\x1B[0;36m" 18 | #define C_WHT "\x1B[0;37m" 19 | 20 | //Regular bold text 21 | #define C_BBLK "\x1B[1;30m" 22 | #define C_BRED "\x1B[1;31m" 23 | #define C_BGRN "\x1B[1;32m" 24 | #define C_BYEL "\x1B[1;33m" 25 | #define C_BBLU "\x1B[1;34m" 26 | #define C_BMAG "\x1B[1;35m" 27 | #define C_BCYN "\x1B[1;36m" 28 | #define C_BWHT "\x1B[1;37m" 29 | 30 | //Regular underline text 31 | #define C_UBLK "\x1B[4;30m" 32 | #define C_URED "\x1B[4;31m" 33 | #define C_UGRN "\x1B[4;32m" 34 | #define C_UYEL "\x1B[4;33m" 35 | #define C_UBLU "\x1B[4;34m" 36 | #define C_UMAG "\x1B[4;35m" 37 | #define C_UCYN "\x1B[4;36m" 38 | #define C_UWHT "\x1B[4;37m" 39 | 40 | //Regular background 41 | #define C_BLKB "\x1B[40m" 42 | #define C_REDB "\x1B[41m" 43 | #define C_GRNB "\x1B[42m" 44 | #define C_YELB "\x1B[43m" 45 | #define C_BLUB "\x1B[44m" 46 | #define C_MAGB "\x1B[45m" 47 | #define C_CYNB "\x1B[46m" 48 | #define C_WHTB "\x1B[47m" 49 | 50 | //High intensty background 51 | #define C_BLKHB "\x1B[0;100m" 52 | #define C_REDHB "\x1B[0;101m" 53 | #define C_GRNHB "\x1B[0;102m" 54 | #define C_YELHB "\x1B[0;103m" 55 | #define C_BLUHB "\x1B[0;104m" 56 | #define C_MAGHB "\x1B[0;105m" 57 | #define C_CYNHB "\x1B[0;106m" 58 | #define C_WHTHB "\x1B[0;107m" 59 | 60 | //High intensty text 61 | #define C_HBLK "\x1B[0;90m" 62 | #define C_HRED "\x1B[0;91m" 63 | #define C_HGRN "\x1B[0;92m" 64 | #define C_HYEL "\x1B[0;93m" 65 | #define C_HBLU "\x1B[0;94m" 66 | #define C_HMAG "\x1B[0;95m" 67 | #define C_HCYN "\x1B[0;96m" 68 | #define C_HWHT "\x1B[0;97m" 69 | 70 | //Bold high intensity text 71 | #define C_BHBLK "\x1B[1;90m" 72 | #define C_BHRED "\x1B[1;91m" 73 | #define C_BHGRN "\x1B[1;92m" 74 | #define C_BHYEL "\x1B[1;93m" 75 | #define C_BHBLU "\x1B[1;94m" 76 | #define C_BHMAG "\x1B[1;95m" 77 | #define C_BHCYN "\x1B[1;96m" 78 | #define C_BHWHT "\x1B[1;97m" 79 | 80 | //Reset 81 | #define C_RESET "\x1B[0m" 82 | 83 | #endif /* CANIME_COLORS_H */ 84 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "common.h" 7 | #include "colors.h" 8 | 9 | void die(const char *fmt, ...) 10 | { 11 | va_list args; 12 | va_start(args, fmt); 13 | 14 | fputs(C_BRED, stderr); 15 | vfprintf(stderr, fmt, args); 16 | fputc('\n', stderr); 17 | fputs(C_RESET, stderr); 18 | 19 | va_end(args); 20 | exit(EXIT_FAILURE); 21 | } 22 | 23 | void warn(const char *fmt, ...) 24 | { 25 | va_list args; 26 | va_start(args, fmt); 27 | 28 | fputs(C_BRED, stderr); 29 | vfprintf(stderr, fmt, args); 30 | fputc('\n', stderr); 31 | fputs(C_RESET, stderr); 32 | 33 | va_end(args); 34 | } 35 | 36 | void *xmalloc(size_t size) 37 | { 38 | void *ptr = malloc(size); 39 | if (ptr == NULL) { 40 | die("malloc: %s", strerror(errno)); 41 | } 42 | 43 | return ptr; 44 | } 45 | 46 | void *xrealloc(void *ptr, size_t size) 47 | { 48 | void *tmp = realloc(ptr, size); 49 | if (tmp == NULL) { 50 | die("realloc: %s", strerror(errno)); 51 | } 52 | 53 | return tmp; 54 | } 55 | 56 | char *xstrdup(const char *str) 57 | { 58 | char *tmp = strdup(str); 59 | if (tmp == NULL) { 60 | die("strdup: %s", strerror(errno)); 61 | } 62 | 63 | return tmp; 64 | } 65 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_COMMON_H 2 | #define CANIME_COMMON_H 3 | 4 | #include 5 | 6 | #define ARRAY_SIZE(arr) (sizeof((arr)) / sizeof((arr)[0])) 7 | 8 | void die(const char *fmt, ...); 9 | void warn(const char *fmt, ...); 10 | void *xmalloc(size_t size); 11 | void *xrealloc(void *ptr, size_t size); 12 | char *xstrdup(const char *str); 13 | 14 | #endif /* CANIME_COMMON_H */ 15 | -------------------------------------------------------------------------------- /src/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "input.h" 6 | #include "anime.h" 7 | #include "common.h" 8 | #include "colors.h" 9 | 10 | // ----------------------------------------------------------------------------- 11 | // Private Functions 12 | // ----------------------------------------------------------------------------- 13 | static void print_search_results(struct SearchResults *search_results) 14 | { 15 | char *color; 16 | char *fmt = "%s[%s%d%s]%s %s%s%s\n"; 17 | 18 | if (search_results->total > MAX_ANIME_SEARCH_RESULTS) 19 | search_results->total = MAX_ANIME_SEARCH_RESULTS; 20 | 21 | // print with colors 22 | for (int i = search_results->total - 1; i >= 0; i--) { 23 | color = (i % 2 == 0) ? C_BYEL : C_RESET; 24 | printf(fmt, C_BBLU, C_BCYN, i + 1, C_BBLU, C_RESET, color, 25 | search_results->results[i], C_RESET); 26 | } 27 | } 28 | 29 | static void print_options() 30 | { 31 | char *fmt = "%s[%s%c%s]%s %s%s%s\n"; 32 | 33 | printf(fmt, C_BBLU, C_BCYN, 'n', C_BBLU, C_RESET, 34 | C_BYEL, "next episode", C_RESET); 35 | printf(fmt, C_BBLU, C_BCYN, 'p', C_BBLU, C_RESET, 36 | C_BMAG, "previous episode", C_RESET); 37 | printf(fmt, C_BBLU, C_BCYN, 's', C_BBLU, C_RESET, 38 | C_BYEL, "select episode", C_RESET); 39 | printf(fmt, C_BBLU, C_BCYN, 'r', C_BBLU, C_RESET, 40 | C_BMAG, "replay episode", C_RESET); 41 | printf(fmt, C_BBLU, C_BCYN, 'q', C_BBLU, C_RESET, 42 | C_BRED, "quit", C_RESET); 43 | } 44 | 45 | static bool handle_option_choice(char choice, struct AnimeInfo *anime) 46 | { 47 | switch (choice) { 48 | case 'n': 49 | anime->current_episode++; 50 | break; 51 | 52 | case 'p': 53 | anime->current_episode--; 54 | break; 55 | 56 | case 'r': 57 | // Do nothing just play it back again 58 | break; 59 | 60 | case 's': 61 | // ask_episode_sel() checks if episode is out of range 62 | anime->current_episode = ask_episode_sel(anime->total_episodes); 63 | return false; 64 | 65 | case 'q': 66 | return true; 67 | 68 | default: 69 | warn("Invalid Choice"); 70 | return true; 71 | }; 72 | 73 | if (anime->current_episode < 1 || 74 | anime->current_episode > anime->total_episodes) { 75 | // canime shouldn't die here, we have to write history! 76 | warn("Episode out of range"); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | static void flushstdin() 84 | { 85 | char c; 86 | while ((c = getchar()) != '\n' && c != EOF); 87 | } 88 | 89 | static void safe_scanf(const char *fmt, ...) 90 | { 91 | va_list args; 92 | va_start(args, fmt); 93 | 94 | int result = vfscanf(stdin, fmt, args); 95 | if (result == 0) { 96 | die("Invalid input"); 97 | flushstdin(); 98 | } else if (result == EOF) { 99 | die("EOF detected; Bailing out!"); 100 | } 101 | 102 | flushstdin(); 103 | 104 | va_end(args); 105 | } 106 | 107 | // ----------------------------------------------------------------------------- 108 | // Non-Private Functions 109 | // ----------------------------------------------------------------------------- 110 | char *ask_search_query() 111 | { 112 | static char anime_name[MAX_ANIME_NAME_LEN]; 113 | fputs("Enter Anime: ", stdout); 114 | fgets(anime_name, sizeof(anime_name), stdin); 115 | 116 | return anime_name; 117 | } 118 | 119 | int ask_anime_sel(struct SearchResults *search_results) 120 | { 121 | int sel; 122 | 123 | print_search_results(search_results); 124 | printf("%sEnter Selection:%s ", C_BBLU, C_RESET); 125 | safe_scanf("%d", &sel); 126 | 127 | if (sel < 1 || sel > MAX_ANIME_SEARCH_RESULTS) 128 | die("Invalid Selection"); 129 | 130 | return sel - 1; 131 | } 132 | 133 | int ask_episode_sel(int total_episodes) 134 | { 135 | int sel; 136 | printf("%sChoose Episode %s[1-%d]%s: ", C_BBLU, C_BCYN, total_episodes, 137 | C_RESET); 138 | safe_scanf("%d", &sel); 139 | 140 | if (sel < 1 || sel > total_episodes) 141 | die("Invalid Episode"); 142 | 143 | return sel; 144 | } 145 | 146 | bool ask_option_choice(struct AnimeInfo *anime) 147 | { 148 | char choice; 149 | 150 | print_options(); 151 | printf("%sEnter Choice%s: ", C_BBLU, C_RESET); 152 | safe_scanf(" %c", &choice); 153 | 154 | return handle_option_choice(choice, anime); 155 | } 156 | -------------------------------------------------------------------------------- /src/input.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_INPUT_H 2 | #define CANIME_INPUT_H 3 | 4 | #include 5 | 6 | struct AnimeInfo; 7 | struct SearchResults; 8 | 9 | // Ask user for search query 10 | char *ask_search_query(); 11 | 12 | // Ask user for anime selection 13 | int ask_anime_sel(struct SearchResults *search_results); 14 | 15 | // Ask user for episode selection 16 | int ask_episode_sel(int total_episodes); 17 | 18 | // Ask user for option selection 19 | // @returns true if program should quit 20 | bool ask_option_choice(struct AnimeInfo *anime); 21 | 22 | #endif /* CANIME_INPUT_H */ 23 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "anime.h" 5 | #include "input.h" 6 | #include "common.h" 7 | #include "colors.h" 8 | #include "web_client.h" 9 | #include "provider.h" 10 | #include "utils.h" 11 | 12 | #define DEFAULT_PROVIDER "gogoanime" 13 | 14 | // ----------------------------------------------------------------------------- 15 | // Local Variables 16 | // ----------------------------------------------------------------------------- 17 | static char *provider = DEFAULT_PROVIDER; 18 | static struct AnimeProvider *anime_provider = NULL; 19 | static char *progname = NULL; 20 | static char *query = NULL; 21 | static struct AnimeInfo *anime = NULL; 22 | 23 | // ----------------------------------------------------------------------------- 24 | // Function Declarations 25 | // ----------------------------------------------------------------------------- 26 | void init(); 27 | void cleanup(); 28 | void get_initial_input(); 29 | void run(); 30 | void open_episode(); 31 | void usage(); 32 | 33 | // ----------------------------------------------------------------------------- 34 | // Function Definitions 35 | // ----------------------------------------------------------------------------- 36 | void init() 37 | { 38 | // Get the anime provider to use 39 | anime_provider = get_anime_provider(provider); 40 | if (anime_provider == NULL) 41 | die("Invalid Provider: %s", provider); 42 | 43 | // Initialize the web_client 44 | web_client_init(); 45 | } 46 | 47 | void cleanup() 48 | { 49 | web_client_cleanup(); 50 | } 51 | 52 | void get_initial_input() 53 | { 54 | int anime_sel_id; 55 | int episode_sel = 1; 56 | struct SearchResults *search_results = NULL; 57 | 58 | // If user didn't give query as argument. Then, ask for query 59 | if (query == NULL) 60 | query = ask_search_query(); 61 | 62 | // Search the provider using the given query 63 | search_results = anime_provider->search(query); 64 | if (search_results->total < 1) { 65 | // Cleanup all the stuff 66 | cleanup(); 67 | die("Couldn't find %s. Use a better search term.", query); 68 | } 69 | 70 | // Get anime selection from user 71 | anime_sel_id = ask_anime_sel(search_results); 72 | anime = anime_provider->get_metadata(search_results->results[anime_sel_id]); 73 | 74 | // Get episode selection from user 75 | if (anime->total_episodes > 1) 76 | episode_sel = ask_episode_sel(anime->total_episodes); 77 | 78 | anime->current_episode = episode_sel; 79 | } 80 | 81 | void run() 82 | { 83 | open_episode(); 84 | 85 | char choice; 86 | while (1) { 87 | printf("%sCurrent playing %s episode %s%d/%d%s\n", C_BGRN, anime->title, 88 | C_BCYN, anime->current_episode, anime->total_episodes, C_RESET); 89 | 90 | if (ask_option_choice(anime)) break; 91 | open_episode(); 92 | } 93 | 94 | free(anime); 95 | } 96 | 97 | void open_episode() 98 | { 99 | // Clear the screen 100 | // TODO: Make this portable. Maybe use ncurses or something? 101 | fputs("\x1B[2J\x1B[1;1H", stdout); 102 | 103 | printf("Getting data for episode %d\n\n", anime->current_episode); 104 | anime_provider->get_sources(anime); 105 | play_episode(anime); 106 | } 107 | 108 | 109 | void usage() 110 | { 111 | die("USAGE: %s [OPTION...] QUERY\n" 112 | " -h show this help text\n" 113 | " -p set provider to scrap\n" 114 | " -d download episode\n" 115 | " -H continue where you left off", 116 | progname); 117 | } 118 | 119 | int main(int argc, char *argv[]) 120 | { 121 | progname = argv[0]; 122 | 123 | if (argc < 2) 124 | goto main_code; 125 | 126 | int opt; 127 | while ((opt = getopt(argc, argv, "hHdp:")) != -1) { 128 | switch (opt) { 129 | case 'h': 130 | usage(); 131 | break; 132 | 133 | case 'H': 134 | break; 135 | 136 | case 'd': 137 | break; 138 | 139 | case 'p': 140 | provider = optarg; 141 | break; 142 | 143 | default: /* '?' */ 144 | usage(); 145 | break; 146 | } 147 | } 148 | 149 | main_code: 150 | 151 | if (optind < argc) 152 | query = argv[optind]; 153 | 154 | init(); 155 | get_initial_input(); 156 | run(); 157 | cleanup(); 158 | 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /src/parser/json.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | /* disable warnings about old C89 functions in MSVC */ 27 | #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) 28 | #define _CRT_SECURE_NO_DEPRECATE 29 | #endif 30 | 31 | #ifdef __GNUC__ 32 | #pragma GCC visibility push(default) 33 | #endif 34 | #if defined(_MSC_VER) 35 | #pragma warning (push) 36 | /* disable warning about single line comments in system headers */ 37 | #pragma warning (disable : 4001) 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #ifdef ENABLE_LOCALES 49 | #include 50 | #endif 51 | 52 | #if defined(_MSC_VER) 53 | #pragma warning (pop) 54 | #endif 55 | #ifdef __GNUC__ 56 | #pragma GCC visibility pop 57 | #endif 58 | 59 | #include "json.h" 60 | 61 | /* define our own boolean type */ 62 | #ifdef true 63 | #undef true 64 | #endif 65 | #define true ((cJSON_bool)1) 66 | 67 | #ifdef false 68 | #undef false 69 | #endif 70 | #define false ((cJSON_bool)0) 71 | 72 | /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ 73 | #ifndef isinf 74 | #define isinf(d) (isnan((d - d)) && !isnan(d)) 75 | #endif 76 | #ifndef isnan 77 | #define isnan(d) (d != d) 78 | #endif 79 | 80 | #ifndef NAN 81 | #ifdef _WIN32 82 | #define NAN sqrt(-1.0) 83 | #else 84 | #define NAN 0.0/0.0 85 | #endif 86 | #endif 87 | 88 | typedef struct { 89 | const unsigned char *json; 90 | size_t position; 91 | } error; 92 | static error global_error = { NULL, 0 }; 93 | 94 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) 95 | { 96 | return (const char*) (global_error.json + global_error.position); 97 | } 98 | 99 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) 100 | { 101 | if (!cJSON_IsString(item)) 102 | { 103 | return NULL; 104 | } 105 | 106 | return item->valuestring; 107 | } 108 | 109 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) 110 | { 111 | if (!cJSON_IsNumber(item)) 112 | { 113 | return (double) NAN; 114 | } 115 | 116 | return item->valuedouble; 117 | } 118 | 119 | /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 120 | #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) 121 | #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 122 | #endif 123 | 124 | CJSON_PUBLIC(const char*) cJSON_Version(void) 125 | { 126 | static char version[15]; 127 | sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 128 | 129 | return version; 130 | } 131 | 132 | /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ 133 | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) 134 | { 135 | if ((string1 == NULL) || (string2 == NULL)) 136 | { 137 | return 1; 138 | } 139 | 140 | if (string1 == string2) 141 | { 142 | return 0; 143 | } 144 | 145 | for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 146 | { 147 | if (*string1 == '\0') 148 | { 149 | return 0; 150 | } 151 | } 152 | 153 | return tolower(*string1) - tolower(*string2); 154 | } 155 | 156 | typedef struct internal_hooks 157 | { 158 | void *(CJSON_CDECL *allocate)(size_t size); 159 | void (CJSON_CDECL *deallocate)(void *pointer); 160 | void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); 161 | } internal_hooks; 162 | 163 | #if defined(_MSC_VER) 164 | /* work around MSVC error C2322: '...' address of dllimport '...' is not static */ 165 | static void * CJSON_CDECL internal_malloc(size_t size) 166 | { 167 | return malloc(size); 168 | } 169 | static void CJSON_CDECL internal_free(void *pointer) 170 | { 171 | free(pointer); 172 | } 173 | static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) 174 | { 175 | return realloc(pointer, size); 176 | } 177 | #else 178 | #define internal_malloc malloc 179 | #define internal_free free 180 | #define internal_realloc realloc 181 | #endif 182 | 183 | /* strlen of character literals resolved at compile time */ 184 | #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 185 | 186 | static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; 187 | 188 | static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) 189 | { 190 | size_t length = 0; 191 | unsigned char *copy = NULL; 192 | 193 | if (string == NULL) 194 | { 195 | return NULL; 196 | } 197 | 198 | length = strlen((const char*)string) + sizeof(""); 199 | copy = (unsigned char*)hooks->allocate(length); 200 | if (copy == NULL) 201 | { 202 | return NULL; 203 | } 204 | memcpy(copy, string, length); 205 | 206 | return copy; 207 | } 208 | 209 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) 210 | { 211 | if (hooks == NULL) 212 | { 213 | /* Reset hooks */ 214 | global_hooks.allocate = malloc; 215 | global_hooks.deallocate = free; 216 | global_hooks.reallocate = realloc; 217 | return; 218 | } 219 | 220 | global_hooks.allocate = malloc; 221 | if (hooks->malloc_fn != NULL) 222 | { 223 | global_hooks.allocate = hooks->malloc_fn; 224 | } 225 | 226 | global_hooks.deallocate = free; 227 | if (hooks->free_fn != NULL) 228 | { 229 | global_hooks.deallocate = hooks->free_fn; 230 | } 231 | 232 | /* use realloc only if both free and malloc are used */ 233 | global_hooks.reallocate = NULL; 234 | if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) 235 | { 236 | global_hooks.reallocate = realloc; 237 | } 238 | } 239 | 240 | /* Internal constructor. */ 241 | static cJSON *cJSON_New_Item(const internal_hooks * const hooks) 242 | { 243 | cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); 244 | if (node) 245 | { 246 | memset(node, '\0', sizeof(cJSON)); 247 | } 248 | 249 | return node; 250 | } 251 | 252 | /* Delete a cJSON structure. */ 253 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) 254 | { 255 | cJSON *next = NULL; 256 | while (item != NULL) 257 | { 258 | next = item->next; 259 | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) 260 | { 261 | cJSON_Delete(item->child); 262 | } 263 | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) 264 | { 265 | global_hooks.deallocate(item->valuestring); 266 | } 267 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 268 | { 269 | global_hooks.deallocate(item->string); 270 | } 271 | global_hooks.deallocate(item); 272 | item = next; 273 | } 274 | } 275 | 276 | /* get the decimal point character of the current locale */ 277 | static unsigned char get_decimal_point(void) 278 | { 279 | #ifdef ENABLE_LOCALES 280 | struct lconv *lconv = localeconv(); 281 | return (unsigned char) lconv->decimal_point[0]; 282 | #else 283 | return '.'; 284 | #endif 285 | } 286 | 287 | typedef struct 288 | { 289 | const unsigned char *content; 290 | size_t length; 291 | size_t offset; 292 | size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ 293 | internal_hooks hooks; 294 | } parse_buffer; 295 | 296 | /* check if the given size is left to read in a given parse buffer (starting with 1) */ 297 | #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) 298 | /* check if the buffer can be accessed at the given index (starting with 0) */ 299 | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) 300 | #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) 301 | /* get a pointer to the buffer at the position */ 302 | #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) 303 | 304 | /* Parse the input text to generate a number, and populate the result into item. */ 305 | static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) 306 | { 307 | double number = 0; 308 | unsigned char *after_end = NULL; 309 | unsigned char number_c_string[64]; 310 | unsigned char decimal_point = get_decimal_point(); 311 | size_t i = 0; 312 | 313 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 314 | { 315 | return false; 316 | } 317 | 318 | /* copy the number into a temporary buffer and replace '.' with the decimal point 319 | * of the current locale (for strtod) 320 | * This also takes care of '\0' not necessarily being available for marking the end of the input */ 321 | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) 322 | { 323 | switch (buffer_at_offset(input_buffer)[i]) 324 | { 325 | case '0': 326 | case '1': 327 | case '2': 328 | case '3': 329 | case '4': 330 | case '5': 331 | case '6': 332 | case '7': 333 | case '8': 334 | case '9': 335 | case '+': 336 | case '-': 337 | case 'e': 338 | case 'E': 339 | number_c_string[i] = buffer_at_offset(input_buffer)[i]; 340 | break; 341 | 342 | case '.': 343 | number_c_string[i] = decimal_point; 344 | break; 345 | 346 | default: 347 | goto loop_end; 348 | } 349 | } 350 | loop_end: 351 | number_c_string[i] = '\0'; 352 | 353 | number = strtod((const char*)number_c_string, (char**)&after_end); 354 | if (number_c_string == after_end) 355 | { 356 | return false; /* parse_error */ 357 | } 358 | 359 | item->valuedouble = number; 360 | 361 | /* use saturation in case of overflow */ 362 | if (number >= INT_MAX) 363 | { 364 | item->valueint = INT_MAX; 365 | } 366 | else if (number <= (double)INT_MIN) 367 | { 368 | item->valueint = INT_MIN; 369 | } 370 | else 371 | { 372 | item->valueint = (int)number; 373 | } 374 | 375 | item->type = cJSON_Number; 376 | 377 | input_buffer->offset += (size_t)(after_end - number_c_string); 378 | return true; 379 | } 380 | 381 | /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 382 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) 383 | { 384 | if (number >= INT_MAX) 385 | { 386 | object->valueint = INT_MAX; 387 | } 388 | else if (number <= (double)INT_MIN) 389 | { 390 | object->valueint = INT_MIN; 391 | } 392 | else 393 | { 394 | object->valueint = (int)number; 395 | } 396 | 397 | return object->valuedouble = number; 398 | } 399 | 400 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) 401 | { 402 | char *copy = NULL; 403 | /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ 404 | if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) 405 | { 406 | return NULL; 407 | } 408 | if (strlen(valuestring) <= strlen(object->valuestring)) 409 | { 410 | strcpy(object->valuestring, valuestring); 411 | return object->valuestring; 412 | } 413 | copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); 414 | if (copy == NULL) 415 | { 416 | return NULL; 417 | } 418 | if (object->valuestring != NULL) 419 | { 420 | cJSON_free(object->valuestring); 421 | } 422 | object->valuestring = copy; 423 | 424 | return copy; 425 | } 426 | 427 | typedef struct 428 | { 429 | unsigned char *buffer; 430 | size_t length; 431 | size_t offset; 432 | size_t depth; /* current nesting depth (for formatted printing) */ 433 | cJSON_bool noalloc; 434 | cJSON_bool format; /* is this print a formatted print */ 435 | internal_hooks hooks; 436 | } printbuffer; 437 | 438 | /* realloc printbuffer if necessary to have at least "needed" bytes more */ 439 | static unsigned char* ensure(printbuffer * const p, size_t needed) 440 | { 441 | unsigned char *newbuffer = NULL; 442 | size_t newsize = 0; 443 | 444 | if ((p == NULL) || (p->buffer == NULL)) 445 | { 446 | return NULL; 447 | } 448 | 449 | if ((p->length > 0) && (p->offset >= p->length)) 450 | { 451 | /* make sure that offset is valid */ 452 | return NULL; 453 | } 454 | 455 | if (needed > INT_MAX) 456 | { 457 | /* sizes bigger than INT_MAX are currently not supported */ 458 | return NULL; 459 | } 460 | 461 | needed += p->offset + 1; 462 | if (needed <= p->length) 463 | { 464 | return p->buffer + p->offset; 465 | } 466 | 467 | if (p->noalloc) { 468 | return NULL; 469 | } 470 | 471 | /* calculate new buffer size */ 472 | if (needed > (INT_MAX / 2)) 473 | { 474 | /* overflow of int, use INT_MAX if possible */ 475 | if (needed <= INT_MAX) 476 | { 477 | newsize = INT_MAX; 478 | } 479 | else 480 | { 481 | return NULL; 482 | } 483 | } 484 | else 485 | { 486 | newsize = needed * 2; 487 | } 488 | 489 | if (p->hooks.reallocate != NULL) 490 | { 491 | /* reallocate with realloc if available */ 492 | newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); 493 | if (newbuffer == NULL) 494 | { 495 | p->hooks.deallocate(p->buffer); 496 | p->length = 0; 497 | p->buffer = NULL; 498 | 499 | return NULL; 500 | } 501 | } 502 | else 503 | { 504 | /* otherwise reallocate manually */ 505 | newbuffer = (unsigned char*)p->hooks.allocate(newsize); 506 | if (!newbuffer) 507 | { 508 | p->hooks.deallocate(p->buffer); 509 | p->length = 0; 510 | p->buffer = NULL; 511 | 512 | return NULL; 513 | } 514 | 515 | memcpy(newbuffer, p->buffer, p->offset + 1); 516 | p->hooks.deallocate(p->buffer); 517 | } 518 | p->length = newsize; 519 | p->buffer = newbuffer; 520 | 521 | return newbuffer + p->offset; 522 | } 523 | 524 | /* calculate the new length of the string in a printbuffer and update the offset */ 525 | static void update_offset(printbuffer * const buffer) 526 | { 527 | const unsigned char *buffer_pointer = NULL; 528 | if ((buffer == NULL) || (buffer->buffer == NULL)) 529 | { 530 | return; 531 | } 532 | buffer_pointer = buffer->buffer + buffer->offset; 533 | 534 | buffer->offset += strlen((const char*)buffer_pointer); 535 | } 536 | 537 | /* securely comparison of floating-point variables */ 538 | static cJSON_bool compare_double(double a, double b) 539 | { 540 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 541 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 542 | } 543 | 544 | /* Render the number nicely from the given item into a string. */ 545 | static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) 546 | { 547 | unsigned char *output_pointer = NULL; 548 | double d = item->valuedouble; 549 | int length = 0; 550 | size_t i = 0; 551 | unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ 552 | unsigned char decimal_point = get_decimal_point(); 553 | double test = 0.0; 554 | 555 | if (output_buffer == NULL) 556 | { 557 | return false; 558 | } 559 | 560 | /* This checks for NaN and Infinity */ 561 | if (isnan(d) || isinf(d)) 562 | { 563 | length = sprintf((char*)number_buffer, "null"); 564 | } 565 | else 566 | { 567 | /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ 568 | length = sprintf((char*)number_buffer, "%1.15g", d); 569 | 570 | /* Check whether the original double can be recovered */ 571 | if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) 572 | { 573 | /* If not, print with 17 decimal places of precision */ 574 | length = sprintf((char*)number_buffer, "%1.17g", d); 575 | } 576 | } 577 | 578 | /* sprintf failed or buffer overrun occurred */ 579 | if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) 580 | { 581 | return false; 582 | } 583 | 584 | /* reserve appropriate space in the output */ 585 | output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); 586 | if (output_pointer == NULL) 587 | { 588 | return false; 589 | } 590 | 591 | /* copy the printed number to the output and replace locale 592 | * dependent decimal point with '.' */ 593 | for (i = 0; i < ((size_t)length); i++) 594 | { 595 | if (number_buffer[i] == decimal_point) 596 | { 597 | output_pointer[i] = '.'; 598 | continue; 599 | } 600 | 601 | output_pointer[i] = number_buffer[i]; 602 | } 603 | output_pointer[i] = '\0'; 604 | 605 | output_buffer->offset += (size_t)length; 606 | 607 | return true; 608 | } 609 | 610 | /* parse 4 digit hexadecimal number */ 611 | static unsigned parse_hex4(const unsigned char * const input) 612 | { 613 | unsigned int h = 0; 614 | size_t i = 0; 615 | 616 | for (i = 0; i < 4; i++) 617 | { 618 | /* parse digit */ 619 | if ((input[i] >= '0') && (input[i] <= '9')) 620 | { 621 | h += (unsigned int) input[i] - '0'; 622 | } 623 | else if ((input[i] >= 'A') && (input[i] <= 'F')) 624 | { 625 | h += (unsigned int) 10 + input[i] - 'A'; 626 | } 627 | else if ((input[i] >= 'a') && (input[i] <= 'f')) 628 | { 629 | h += (unsigned int) 10 + input[i] - 'a'; 630 | } 631 | else /* invalid */ 632 | { 633 | return 0; 634 | } 635 | 636 | if (i < 3) 637 | { 638 | /* shift left to make place for the next nibble */ 639 | h = h << 4; 640 | } 641 | } 642 | 643 | return h; 644 | } 645 | 646 | /* converts a UTF-16 literal to UTF-8 647 | * A literal can be one or two sequences of the form \uXXXX */ 648 | static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) 649 | { 650 | long unsigned int codepoint = 0; 651 | unsigned int first_code = 0; 652 | const unsigned char *first_sequence = input_pointer; 653 | unsigned char utf8_length = 0; 654 | unsigned char utf8_position = 0; 655 | unsigned char sequence_length = 0; 656 | unsigned char first_byte_mark = 0; 657 | 658 | if ((input_end - first_sequence) < 6) 659 | { 660 | /* input ends unexpectedly */ 661 | goto fail; 662 | } 663 | 664 | /* get the first utf16 sequence */ 665 | first_code = parse_hex4(first_sequence + 2); 666 | 667 | /* check that the code is valid */ 668 | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) 669 | { 670 | goto fail; 671 | } 672 | 673 | /* UTF16 surrogate pair */ 674 | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 675 | { 676 | const unsigned char *second_sequence = first_sequence + 6; 677 | unsigned int second_code = 0; 678 | sequence_length = 12; /* \uXXXX\uXXXX */ 679 | 680 | if ((input_end - second_sequence) < 6) 681 | { 682 | /* input ends unexpectedly */ 683 | goto fail; 684 | } 685 | 686 | if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 687 | { 688 | /* missing second half of the surrogate pair */ 689 | goto fail; 690 | } 691 | 692 | /* get the second utf16 sequence */ 693 | second_code = parse_hex4(second_sequence + 2); 694 | /* check that the code is valid */ 695 | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 696 | { 697 | /* invalid second half of the surrogate pair */ 698 | goto fail; 699 | } 700 | 701 | 702 | /* calculate the unicode codepoint from the surrogate pair */ 703 | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 704 | } 705 | else 706 | { 707 | sequence_length = 6; /* \uXXXX */ 708 | codepoint = first_code; 709 | } 710 | 711 | /* encode as UTF-8 712 | * takes at maximum 4 bytes to encode: 713 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 714 | if (codepoint < 0x80) 715 | { 716 | /* normal ascii, encoding 0xxxxxxx */ 717 | utf8_length = 1; 718 | } 719 | else if (codepoint < 0x800) 720 | { 721 | /* two bytes, encoding 110xxxxx 10xxxxxx */ 722 | utf8_length = 2; 723 | first_byte_mark = 0xC0; /* 11000000 */ 724 | } 725 | else if (codepoint < 0x10000) 726 | { 727 | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 728 | utf8_length = 3; 729 | first_byte_mark = 0xE0; /* 11100000 */ 730 | } 731 | else if (codepoint <= 0x10FFFF) 732 | { 733 | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 734 | utf8_length = 4; 735 | first_byte_mark = 0xF0; /* 11110000 */ 736 | } 737 | else 738 | { 739 | /* invalid unicode codepoint */ 740 | goto fail; 741 | } 742 | 743 | /* encode as utf8 */ 744 | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) 745 | { 746 | /* 10xxxxxx */ 747 | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); 748 | codepoint >>= 6; 749 | } 750 | /* encode first byte */ 751 | if (utf8_length > 1) 752 | { 753 | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); 754 | } 755 | else 756 | { 757 | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); 758 | } 759 | 760 | *output_pointer += utf8_length; 761 | 762 | return sequence_length; 763 | 764 | fail: 765 | return 0; 766 | } 767 | 768 | /* Parse the input text into an unescaped cinput, and populate item. */ 769 | static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) 770 | { 771 | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; 772 | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; 773 | unsigned char *output_pointer = NULL; 774 | unsigned char *output = NULL; 775 | 776 | /* not a string */ 777 | if (buffer_at_offset(input_buffer)[0] != '\"') 778 | { 779 | goto fail; 780 | } 781 | 782 | { 783 | /* calculate approximate size of the output (overestimate) */ 784 | size_t allocation_length = 0; 785 | size_t skipped_bytes = 0; 786 | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) 787 | { 788 | /* is escape sequence */ 789 | if (input_end[0] == '\\') 790 | { 791 | if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) 792 | { 793 | /* prevent buffer overflow when last input character is a backslash */ 794 | goto fail; 795 | } 796 | skipped_bytes++; 797 | input_end++; 798 | } 799 | input_end++; 800 | } 801 | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) 802 | { 803 | goto fail; /* string ended unexpectedly */ 804 | } 805 | 806 | /* This is at most how much we need for the output */ 807 | allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; 808 | output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); 809 | if (output == NULL) 810 | { 811 | goto fail; /* allocation failure */ 812 | } 813 | } 814 | 815 | output_pointer = output; 816 | /* loop through the string literal */ 817 | while (input_pointer < input_end) 818 | { 819 | if (*input_pointer != '\\') 820 | { 821 | *output_pointer++ = *input_pointer++; 822 | } 823 | /* escape sequence */ 824 | else 825 | { 826 | unsigned char sequence_length = 2; 827 | if ((input_end - input_pointer) < 1) 828 | { 829 | goto fail; 830 | } 831 | 832 | switch (input_pointer[1]) 833 | { 834 | case 'b': 835 | *output_pointer++ = '\b'; 836 | break; 837 | case 'f': 838 | *output_pointer++ = '\f'; 839 | break; 840 | case 'n': 841 | *output_pointer++ = '\n'; 842 | break; 843 | case 'r': 844 | *output_pointer++ = '\r'; 845 | break; 846 | case 't': 847 | *output_pointer++ = '\t'; 848 | break; 849 | case '\"': 850 | case '\\': 851 | case '/': 852 | *output_pointer++ = input_pointer[1]; 853 | break; 854 | 855 | /* UTF-16 literal */ 856 | case 'u': 857 | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); 858 | if (sequence_length == 0) 859 | { 860 | /* failed to convert UTF16-literal to UTF-8 */ 861 | goto fail; 862 | } 863 | break; 864 | 865 | default: 866 | goto fail; 867 | } 868 | input_pointer += sequence_length; 869 | } 870 | } 871 | 872 | /* zero terminate the output */ 873 | *output_pointer = '\0'; 874 | 875 | item->type = cJSON_String; 876 | item->valuestring = (char*)output; 877 | 878 | input_buffer->offset = (size_t) (input_end - input_buffer->content); 879 | input_buffer->offset++; 880 | 881 | return true; 882 | 883 | fail: 884 | if (output != NULL) 885 | { 886 | input_buffer->hooks.deallocate(output); 887 | } 888 | 889 | if (input_pointer != NULL) 890 | { 891 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); 892 | } 893 | 894 | return false; 895 | } 896 | 897 | /* Render the cstring provided to an escaped version that can be printed. */ 898 | static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 899 | { 900 | const unsigned char *input_pointer = NULL; 901 | unsigned char *output = NULL; 902 | unsigned char *output_pointer = NULL; 903 | size_t output_length = 0; 904 | /* numbers of additional characters needed for escaping */ 905 | size_t escape_characters = 0; 906 | 907 | if (output_buffer == NULL) 908 | { 909 | return false; 910 | } 911 | 912 | /* empty string */ 913 | if (input == NULL) 914 | { 915 | output = ensure(output_buffer, sizeof("\"\"")); 916 | if (output == NULL) 917 | { 918 | return false; 919 | } 920 | strcpy((char*)output, "\"\""); 921 | 922 | return true; 923 | } 924 | 925 | /* set "flag" to 1 if something needs to be escaped */ 926 | for (input_pointer = input; *input_pointer; input_pointer++) 927 | { 928 | switch (*input_pointer) 929 | { 930 | case '\"': 931 | case '\\': 932 | case '\b': 933 | case '\f': 934 | case '\n': 935 | case '\r': 936 | case '\t': 937 | /* one character escape sequence */ 938 | escape_characters++; 939 | break; 940 | default: 941 | if (*input_pointer < 32) 942 | { 943 | /* UTF-16 escape sequence uXXXX */ 944 | escape_characters += 5; 945 | } 946 | break; 947 | } 948 | } 949 | output_length = (size_t)(input_pointer - input) + escape_characters; 950 | 951 | output = ensure(output_buffer, output_length + sizeof("\"\"")); 952 | if (output == NULL) 953 | { 954 | return false; 955 | } 956 | 957 | /* no characters have to be escaped */ 958 | if (escape_characters == 0) 959 | { 960 | output[0] = '\"'; 961 | memcpy(output + 1, input, output_length); 962 | output[output_length + 1] = '\"'; 963 | output[output_length + 2] = '\0'; 964 | 965 | return true; 966 | } 967 | 968 | output[0] = '\"'; 969 | output_pointer = output + 1; 970 | /* copy the string */ 971 | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 972 | { 973 | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 974 | { 975 | /* normal character, copy */ 976 | *output_pointer = *input_pointer; 977 | } 978 | else 979 | { 980 | /* character needs to be escaped */ 981 | *output_pointer++ = '\\'; 982 | switch (*input_pointer) 983 | { 984 | case '\\': 985 | *output_pointer = '\\'; 986 | break; 987 | case '\"': 988 | *output_pointer = '\"'; 989 | break; 990 | case '\b': 991 | *output_pointer = 'b'; 992 | break; 993 | case '\f': 994 | *output_pointer = 'f'; 995 | break; 996 | case '\n': 997 | *output_pointer = 'n'; 998 | break; 999 | case '\r': 1000 | *output_pointer = 'r'; 1001 | break; 1002 | case '\t': 1003 | *output_pointer = 't'; 1004 | break; 1005 | default: 1006 | /* escape and print as unicode codepoint */ 1007 | sprintf((char*)output_pointer, "u%04x", *input_pointer); 1008 | output_pointer += 4; 1009 | break; 1010 | } 1011 | } 1012 | } 1013 | output[output_length + 1] = '\"'; 1014 | output[output_length + 2] = '\0'; 1015 | 1016 | return true; 1017 | } 1018 | 1019 | /* Invoke print_string_ptr (which is useful) on an item. */ 1020 | static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) 1021 | { 1022 | return print_string_ptr((unsigned char*)item->valuestring, p); 1023 | } 1024 | 1025 | /* Predeclare these prototypes. */ 1026 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); 1027 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); 1028 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); 1029 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); 1030 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); 1031 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); 1032 | 1033 | /* Utility to jump whitespace and cr/lf */ 1034 | static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) 1035 | { 1036 | if ((buffer == NULL) || (buffer->content == NULL)) 1037 | { 1038 | return NULL; 1039 | } 1040 | 1041 | if (cannot_access_at_index(buffer, 0)) 1042 | { 1043 | return buffer; 1044 | } 1045 | 1046 | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) 1047 | { 1048 | buffer->offset++; 1049 | } 1050 | 1051 | if (buffer->offset == buffer->length) 1052 | { 1053 | buffer->offset--; 1054 | } 1055 | 1056 | return buffer; 1057 | } 1058 | 1059 | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ 1060 | static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) 1061 | { 1062 | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) 1063 | { 1064 | return NULL; 1065 | } 1066 | 1067 | if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) 1068 | { 1069 | buffer->offset += 3; 1070 | } 1071 | 1072 | return buffer; 1073 | } 1074 | 1075 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) 1076 | { 1077 | size_t buffer_length; 1078 | 1079 | if (NULL == value) 1080 | { 1081 | return NULL; 1082 | } 1083 | 1084 | /* Adding null character size due to require_null_terminated. */ 1085 | buffer_length = strlen(value) + sizeof(""); 1086 | 1087 | return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); 1088 | } 1089 | 1090 | /* Parse an object - create a new root, and populate. */ 1091 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) 1092 | { 1093 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; 1094 | cJSON *item = NULL; 1095 | 1096 | /* reset error position */ 1097 | global_error.json = NULL; 1098 | global_error.position = 0; 1099 | 1100 | if (value == NULL || 0 == buffer_length) 1101 | { 1102 | goto fail; 1103 | } 1104 | 1105 | buffer.content = (const unsigned char*)value; 1106 | buffer.length = buffer_length; 1107 | buffer.offset = 0; 1108 | buffer.hooks = global_hooks; 1109 | 1110 | item = cJSON_New_Item(&global_hooks); 1111 | if (item == NULL) /* memory fail */ 1112 | { 1113 | goto fail; 1114 | } 1115 | 1116 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) 1117 | { 1118 | /* parse failure. ep is set. */ 1119 | goto fail; 1120 | } 1121 | 1122 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 1123 | if (require_null_terminated) 1124 | { 1125 | buffer_skip_whitespace(&buffer); 1126 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') 1127 | { 1128 | goto fail; 1129 | } 1130 | } 1131 | if (return_parse_end) 1132 | { 1133 | *return_parse_end = (const char*)buffer_at_offset(&buffer); 1134 | } 1135 | 1136 | return item; 1137 | 1138 | fail: 1139 | if (item != NULL) 1140 | { 1141 | cJSON_Delete(item); 1142 | } 1143 | 1144 | if (value != NULL) 1145 | { 1146 | error local_error; 1147 | local_error.json = (const unsigned char*)value; 1148 | local_error.position = 0; 1149 | 1150 | if (buffer.offset < buffer.length) 1151 | { 1152 | local_error.position = buffer.offset; 1153 | } 1154 | else if (buffer.length > 0) 1155 | { 1156 | local_error.position = buffer.length - 1; 1157 | } 1158 | 1159 | if (return_parse_end != NULL) 1160 | { 1161 | *return_parse_end = (const char*)local_error.json + local_error.position; 1162 | } 1163 | 1164 | global_error = local_error; 1165 | } 1166 | 1167 | return NULL; 1168 | } 1169 | 1170 | /* Default options for cJSON_Parse */ 1171 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) 1172 | { 1173 | return cJSON_ParseWithOpts(value, 0, 0); 1174 | } 1175 | 1176 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) 1177 | { 1178 | return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); 1179 | } 1180 | 1181 | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) 1182 | 1183 | static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) 1184 | { 1185 | static const size_t default_buffer_size = 256; 1186 | printbuffer buffer[1]; 1187 | unsigned char *printed = NULL; 1188 | 1189 | memset(buffer, 0, sizeof(buffer)); 1190 | 1191 | /* create buffer */ 1192 | buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); 1193 | buffer->length = default_buffer_size; 1194 | buffer->format = format; 1195 | buffer->hooks = *hooks; 1196 | if (buffer->buffer == NULL) 1197 | { 1198 | goto fail; 1199 | } 1200 | 1201 | /* print the value */ 1202 | if (!print_value(item, buffer)) 1203 | { 1204 | goto fail; 1205 | } 1206 | update_offset(buffer); 1207 | 1208 | /* check if reallocate is available */ 1209 | if (hooks->reallocate != NULL) 1210 | { 1211 | printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); 1212 | if (printed == NULL) { 1213 | goto fail; 1214 | } 1215 | buffer->buffer = NULL; 1216 | } 1217 | else /* otherwise copy the JSON over to a new buffer */ 1218 | { 1219 | printed = (unsigned char*) hooks->allocate(buffer->offset + 1); 1220 | if (printed == NULL) 1221 | { 1222 | goto fail; 1223 | } 1224 | memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); 1225 | printed[buffer->offset] = '\0'; /* just to be sure */ 1226 | 1227 | /* free the buffer */ 1228 | hooks->deallocate(buffer->buffer); 1229 | } 1230 | 1231 | return printed; 1232 | 1233 | fail: 1234 | if (buffer->buffer != NULL) 1235 | { 1236 | hooks->deallocate(buffer->buffer); 1237 | } 1238 | 1239 | if (printed != NULL) 1240 | { 1241 | hooks->deallocate(printed); 1242 | } 1243 | 1244 | return NULL; 1245 | } 1246 | 1247 | /* Render a cJSON item/entity/structure to text. */ 1248 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) 1249 | { 1250 | return (char*)print(item, true, &global_hooks); 1251 | } 1252 | 1253 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) 1254 | { 1255 | return (char*)print(item, false, &global_hooks); 1256 | } 1257 | 1258 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) 1259 | { 1260 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1261 | 1262 | if (prebuffer < 0) 1263 | { 1264 | return NULL; 1265 | } 1266 | 1267 | p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); 1268 | if (!p.buffer) 1269 | { 1270 | return NULL; 1271 | } 1272 | 1273 | p.length = (size_t)prebuffer; 1274 | p.offset = 0; 1275 | p.noalloc = false; 1276 | p.format = fmt; 1277 | p.hooks = global_hooks; 1278 | 1279 | if (!print_value(item, &p)) 1280 | { 1281 | global_hooks.deallocate(p.buffer); 1282 | return NULL; 1283 | } 1284 | 1285 | return (char*)p.buffer; 1286 | } 1287 | 1288 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 1289 | { 1290 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1291 | 1292 | if ((length < 0) || (buffer == NULL)) 1293 | { 1294 | return false; 1295 | } 1296 | 1297 | p.buffer = (unsigned char*)buffer; 1298 | p.length = (size_t)length; 1299 | p.offset = 0; 1300 | p.noalloc = true; 1301 | p.format = format; 1302 | p.hooks = global_hooks; 1303 | 1304 | return print_value(item, &p); 1305 | } 1306 | 1307 | /* Parser core - when encountering text, process appropriately. */ 1308 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) 1309 | { 1310 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 1311 | { 1312 | return false; /* no input */ 1313 | } 1314 | 1315 | /* parse the different types of values */ 1316 | /* null */ 1317 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) 1318 | { 1319 | item->type = cJSON_NULL; 1320 | input_buffer->offset += 4; 1321 | return true; 1322 | } 1323 | /* false */ 1324 | if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) 1325 | { 1326 | item->type = cJSON_False; 1327 | input_buffer->offset += 5; 1328 | return true; 1329 | } 1330 | /* true */ 1331 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) 1332 | { 1333 | item->type = cJSON_True; 1334 | item->valueint = 1; 1335 | input_buffer->offset += 4; 1336 | return true; 1337 | } 1338 | /* string */ 1339 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) 1340 | { 1341 | return parse_string(item, input_buffer); 1342 | } 1343 | /* number */ 1344 | if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) 1345 | { 1346 | return parse_number(item, input_buffer); 1347 | } 1348 | /* array */ 1349 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) 1350 | { 1351 | return parse_array(item, input_buffer); 1352 | } 1353 | /* object */ 1354 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) 1355 | { 1356 | return parse_object(item, input_buffer); 1357 | } 1358 | 1359 | return false; 1360 | } 1361 | 1362 | /* Render a value to text. */ 1363 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) 1364 | { 1365 | unsigned char *output = NULL; 1366 | 1367 | if ((item == NULL) || (output_buffer == NULL)) 1368 | { 1369 | return false; 1370 | } 1371 | 1372 | switch ((item->type) & 0xFF) 1373 | { 1374 | case cJSON_NULL: 1375 | output = ensure(output_buffer, 5); 1376 | if (output == NULL) 1377 | { 1378 | return false; 1379 | } 1380 | strcpy((char*)output, "null"); 1381 | return true; 1382 | 1383 | case cJSON_False: 1384 | output = ensure(output_buffer, 6); 1385 | if (output == NULL) 1386 | { 1387 | return false; 1388 | } 1389 | strcpy((char*)output, "false"); 1390 | return true; 1391 | 1392 | case cJSON_True: 1393 | output = ensure(output_buffer, 5); 1394 | if (output == NULL) 1395 | { 1396 | return false; 1397 | } 1398 | strcpy((char*)output, "true"); 1399 | return true; 1400 | 1401 | case cJSON_Number: 1402 | return print_number(item, output_buffer); 1403 | 1404 | case cJSON_Raw: 1405 | { 1406 | size_t raw_length = 0; 1407 | if (item->valuestring == NULL) 1408 | { 1409 | return false; 1410 | } 1411 | 1412 | raw_length = strlen(item->valuestring) + sizeof(""); 1413 | output = ensure(output_buffer, raw_length); 1414 | if (output == NULL) 1415 | { 1416 | return false; 1417 | } 1418 | memcpy(output, item->valuestring, raw_length); 1419 | return true; 1420 | } 1421 | 1422 | case cJSON_String: 1423 | return print_string(item, output_buffer); 1424 | 1425 | case cJSON_Array: 1426 | return print_array(item, output_buffer); 1427 | 1428 | case cJSON_Object: 1429 | return print_object(item, output_buffer); 1430 | 1431 | default: 1432 | return false; 1433 | } 1434 | } 1435 | 1436 | /* Build an array from input text. */ 1437 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) 1438 | { 1439 | cJSON *head = NULL; /* head of the linked list */ 1440 | cJSON *current_item = NULL; 1441 | 1442 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1443 | { 1444 | return false; /* to deeply nested */ 1445 | } 1446 | input_buffer->depth++; 1447 | 1448 | if (buffer_at_offset(input_buffer)[0] != '[') 1449 | { 1450 | /* not an array */ 1451 | goto fail; 1452 | } 1453 | 1454 | input_buffer->offset++; 1455 | buffer_skip_whitespace(input_buffer); 1456 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) 1457 | { 1458 | /* empty array */ 1459 | goto success; 1460 | } 1461 | 1462 | /* check if we skipped to the end of the buffer */ 1463 | if (cannot_access_at_index(input_buffer, 0)) 1464 | { 1465 | input_buffer->offset--; 1466 | goto fail; 1467 | } 1468 | 1469 | /* step back to character in front of the first element */ 1470 | input_buffer->offset--; 1471 | /* loop through the comma separated array elements */ 1472 | do 1473 | { 1474 | /* allocate next item */ 1475 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1476 | if (new_item == NULL) 1477 | { 1478 | goto fail; /* allocation failure */ 1479 | } 1480 | 1481 | /* attach next item to list */ 1482 | if (head == NULL) 1483 | { 1484 | /* start the linked list */ 1485 | current_item = head = new_item; 1486 | } 1487 | else 1488 | { 1489 | /* add to the end and advance */ 1490 | current_item->next = new_item; 1491 | new_item->prev = current_item; 1492 | current_item = new_item; 1493 | } 1494 | 1495 | /* parse next value */ 1496 | input_buffer->offset++; 1497 | buffer_skip_whitespace(input_buffer); 1498 | if (!parse_value(current_item, input_buffer)) 1499 | { 1500 | goto fail; /* failed to parse value */ 1501 | } 1502 | buffer_skip_whitespace(input_buffer); 1503 | } 1504 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1505 | 1506 | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') 1507 | { 1508 | goto fail; /* expected end of array */ 1509 | } 1510 | 1511 | success: 1512 | input_buffer->depth--; 1513 | 1514 | if (head != NULL) { 1515 | head->prev = current_item; 1516 | } 1517 | 1518 | item->type = cJSON_Array; 1519 | item->child = head; 1520 | 1521 | input_buffer->offset++; 1522 | 1523 | return true; 1524 | 1525 | fail: 1526 | if (head != NULL) 1527 | { 1528 | cJSON_Delete(head); 1529 | } 1530 | 1531 | return false; 1532 | } 1533 | 1534 | /* Render an array to text */ 1535 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1536 | { 1537 | unsigned char *output_pointer = NULL; 1538 | size_t length = 0; 1539 | cJSON *current_element = item->child; 1540 | 1541 | if (output_buffer == NULL) 1542 | { 1543 | return false; 1544 | } 1545 | 1546 | /* Compose the output array. */ 1547 | /* opening square bracket */ 1548 | output_pointer = ensure(output_buffer, 1); 1549 | if (output_pointer == NULL) 1550 | { 1551 | return false; 1552 | } 1553 | 1554 | *output_pointer = '['; 1555 | output_buffer->offset++; 1556 | output_buffer->depth++; 1557 | 1558 | while (current_element != NULL) 1559 | { 1560 | if (!print_value(current_element, output_buffer)) 1561 | { 1562 | return false; 1563 | } 1564 | update_offset(output_buffer); 1565 | if (current_element->next) 1566 | { 1567 | length = (size_t) (output_buffer->format ? 2 : 1); 1568 | output_pointer = ensure(output_buffer, length + 1); 1569 | if (output_pointer == NULL) 1570 | { 1571 | return false; 1572 | } 1573 | *output_pointer++ = ','; 1574 | if(output_buffer->format) 1575 | { 1576 | *output_pointer++ = ' '; 1577 | } 1578 | *output_pointer = '\0'; 1579 | output_buffer->offset += length; 1580 | } 1581 | current_element = current_element->next; 1582 | } 1583 | 1584 | output_pointer = ensure(output_buffer, 2); 1585 | if (output_pointer == NULL) 1586 | { 1587 | return false; 1588 | } 1589 | *output_pointer++ = ']'; 1590 | *output_pointer = '\0'; 1591 | output_buffer->depth--; 1592 | 1593 | return true; 1594 | } 1595 | 1596 | /* Build an object from the text. */ 1597 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1598 | { 1599 | cJSON *head = NULL; /* linked list head */ 1600 | cJSON *current_item = NULL; 1601 | 1602 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1603 | { 1604 | return false; /* to deeply nested */ 1605 | } 1606 | input_buffer->depth++; 1607 | 1608 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1609 | { 1610 | goto fail; /* not an object */ 1611 | } 1612 | 1613 | input_buffer->offset++; 1614 | buffer_skip_whitespace(input_buffer); 1615 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1616 | { 1617 | goto success; /* empty object */ 1618 | } 1619 | 1620 | /* check if we skipped to the end of the buffer */ 1621 | if (cannot_access_at_index(input_buffer, 0)) 1622 | { 1623 | input_buffer->offset--; 1624 | goto fail; 1625 | } 1626 | 1627 | /* step back to character in front of the first element */ 1628 | input_buffer->offset--; 1629 | /* loop through the comma separated array elements */ 1630 | do 1631 | { 1632 | /* allocate next item */ 1633 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1634 | if (new_item == NULL) 1635 | { 1636 | goto fail; /* allocation failure */ 1637 | } 1638 | 1639 | /* attach next item to list */ 1640 | if (head == NULL) 1641 | { 1642 | /* start the linked list */ 1643 | current_item = head = new_item; 1644 | } 1645 | else 1646 | { 1647 | /* add to the end and advance */ 1648 | current_item->next = new_item; 1649 | new_item->prev = current_item; 1650 | current_item = new_item; 1651 | } 1652 | 1653 | /* parse the name of the child */ 1654 | input_buffer->offset++; 1655 | buffer_skip_whitespace(input_buffer); 1656 | if (!parse_string(current_item, input_buffer)) 1657 | { 1658 | goto fail; /* failed to parse name */ 1659 | } 1660 | buffer_skip_whitespace(input_buffer); 1661 | 1662 | /* swap valuestring and string, because we parsed the name */ 1663 | current_item->string = current_item->valuestring; 1664 | current_item->valuestring = NULL; 1665 | 1666 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1667 | { 1668 | goto fail; /* invalid object */ 1669 | } 1670 | 1671 | /* parse the value */ 1672 | input_buffer->offset++; 1673 | buffer_skip_whitespace(input_buffer); 1674 | if (!parse_value(current_item, input_buffer)) 1675 | { 1676 | goto fail; /* failed to parse value */ 1677 | } 1678 | buffer_skip_whitespace(input_buffer); 1679 | } 1680 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1681 | 1682 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1683 | { 1684 | goto fail; /* expected end of object */ 1685 | } 1686 | 1687 | success: 1688 | input_buffer->depth--; 1689 | 1690 | if (head != NULL) { 1691 | head->prev = current_item; 1692 | } 1693 | 1694 | item->type = cJSON_Object; 1695 | item->child = head; 1696 | 1697 | input_buffer->offset++; 1698 | return true; 1699 | 1700 | fail: 1701 | if (head != NULL) 1702 | { 1703 | cJSON_Delete(head); 1704 | } 1705 | 1706 | return false; 1707 | } 1708 | 1709 | /* Render an object to text. */ 1710 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1711 | { 1712 | unsigned char *output_pointer = NULL; 1713 | size_t length = 0; 1714 | cJSON *current_item = item->child; 1715 | 1716 | if (output_buffer == NULL) 1717 | { 1718 | return false; 1719 | } 1720 | 1721 | /* Compose the output: */ 1722 | length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1723 | output_pointer = ensure(output_buffer, length + 1); 1724 | if (output_pointer == NULL) 1725 | { 1726 | return false; 1727 | } 1728 | 1729 | *output_pointer++ = '{'; 1730 | output_buffer->depth++; 1731 | if (output_buffer->format) 1732 | { 1733 | *output_pointer++ = '\n'; 1734 | } 1735 | output_buffer->offset += length; 1736 | 1737 | while (current_item) 1738 | { 1739 | if (output_buffer->format) 1740 | { 1741 | size_t i; 1742 | output_pointer = ensure(output_buffer, output_buffer->depth); 1743 | if (output_pointer == NULL) 1744 | { 1745 | return false; 1746 | } 1747 | for (i = 0; i < output_buffer->depth; i++) 1748 | { 1749 | *output_pointer++ = '\t'; 1750 | } 1751 | output_buffer->offset += output_buffer->depth; 1752 | } 1753 | 1754 | /* print key */ 1755 | if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1756 | { 1757 | return false; 1758 | } 1759 | update_offset(output_buffer); 1760 | 1761 | length = (size_t) (output_buffer->format ? 2 : 1); 1762 | output_pointer = ensure(output_buffer, length); 1763 | if (output_pointer == NULL) 1764 | { 1765 | return false; 1766 | } 1767 | *output_pointer++ = ':'; 1768 | if (output_buffer->format) 1769 | { 1770 | *output_pointer++ = '\t'; 1771 | } 1772 | output_buffer->offset += length; 1773 | 1774 | /* print value */ 1775 | if (!print_value(current_item, output_buffer)) 1776 | { 1777 | return false; 1778 | } 1779 | update_offset(output_buffer); 1780 | 1781 | /* print comma if not last */ 1782 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1783 | output_pointer = ensure(output_buffer, length + 1); 1784 | if (output_pointer == NULL) 1785 | { 1786 | return false; 1787 | } 1788 | if (current_item->next) 1789 | { 1790 | *output_pointer++ = ','; 1791 | } 1792 | 1793 | if (output_buffer->format) 1794 | { 1795 | *output_pointer++ = '\n'; 1796 | } 1797 | *output_pointer = '\0'; 1798 | output_buffer->offset += length; 1799 | 1800 | current_item = current_item->next; 1801 | } 1802 | 1803 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1804 | if (output_pointer == NULL) 1805 | { 1806 | return false; 1807 | } 1808 | if (output_buffer->format) 1809 | { 1810 | size_t i; 1811 | for (i = 0; i < (output_buffer->depth - 1); i++) 1812 | { 1813 | *output_pointer++ = '\t'; 1814 | } 1815 | } 1816 | *output_pointer++ = '}'; 1817 | *output_pointer = '\0'; 1818 | output_buffer->depth--; 1819 | 1820 | return true; 1821 | } 1822 | 1823 | /* Get Array size/item / object item. */ 1824 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1825 | { 1826 | cJSON *child = NULL; 1827 | size_t size = 0; 1828 | 1829 | if (array == NULL) 1830 | { 1831 | return 0; 1832 | } 1833 | 1834 | child = array->child; 1835 | 1836 | while(child != NULL) 1837 | { 1838 | size++; 1839 | child = child->next; 1840 | } 1841 | 1842 | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1843 | 1844 | return (int)size; 1845 | } 1846 | 1847 | static cJSON* get_array_item(const cJSON *array, size_t index) 1848 | { 1849 | cJSON *current_child = NULL; 1850 | 1851 | if (array == NULL) 1852 | { 1853 | return NULL; 1854 | } 1855 | 1856 | current_child = array->child; 1857 | while ((current_child != NULL) && (index > 0)) 1858 | { 1859 | index--; 1860 | current_child = current_child->next; 1861 | } 1862 | 1863 | return current_child; 1864 | } 1865 | 1866 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1867 | { 1868 | if (index < 0) 1869 | { 1870 | return NULL; 1871 | } 1872 | 1873 | return get_array_item(array, (size_t)index); 1874 | } 1875 | 1876 | static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1877 | { 1878 | cJSON *current_element = NULL; 1879 | 1880 | if ((object == NULL) || (name == NULL)) 1881 | { 1882 | return NULL; 1883 | } 1884 | 1885 | current_element = object->child; 1886 | if (case_sensitive) 1887 | { 1888 | while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1889 | { 1890 | current_element = current_element->next; 1891 | } 1892 | } 1893 | else 1894 | { 1895 | while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1896 | { 1897 | current_element = current_element->next; 1898 | } 1899 | } 1900 | 1901 | if ((current_element == NULL) || (current_element->string == NULL)) { 1902 | return NULL; 1903 | } 1904 | 1905 | return current_element; 1906 | } 1907 | 1908 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1909 | { 1910 | return get_object_item(object, string, false); 1911 | } 1912 | 1913 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1914 | { 1915 | return get_object_item(object, string, true); 1916 | } 1917 | 1918 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1919 | { 1920 | return cJSON_GetObjectItem(object, string) ? 1 : 0; 1921 | } 1922 | 1923 | /* Utility for array list handling. */ 1924 | static void suffix_object(cJSON *prev, cJSON *item) 1925 | { 1926 | prev->next = item; 1927 | item->prev = prev; 1928 | } 1929 | 1930 | /* Utility for handling references. */ 1931 | static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1932 | { 1933 | cJSON *reference = NULL; 1934 | if (item == NULL) 1935 | { 1936 | return NULL; 1937 | } 1938 | 1939 | reference = cJSON_New_Item(hooks); 1940 | if (reference == NULL) 1941 | { 1942 | return NULL; 1943 | } 1944 | 1945 | memcpy(reference, item, sizeof(cJSON)); 1946 | reference->string = NULL; 1947 | reference->type |= cJSON_IsReference; 1948 | reference->next = reference->prev = NULL; 1949 | return reference; 1950 | } 1951 | 1952 | static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1953 | { 1954 | cJSON *child = NULL; 1955 | 1956 | if ((item == NULL) || (array == NULL) || (array == item)) 1957 | { 1958 | return false; 1959 | } 1960 | 1961 | child = array->child; 1962 | /* 1963 | * To find the last item in array quickly, we use prev in array 1964 | */ 1965 | if (child == NULL) 1966 | { 1967 | /* list is empty, start new one */ 1968 | array->child = item; 1969 | item->prev = item; 1970 | item->next = NULL; 1971 | } 1972 | else 1973 | { 1974 | /* append to the end */ 1975 | if (child->prev) 1976 | { 1977 | suffix_object(child->prev, item); 1978 | array->child->prev = item; 1979 | } 1980 | } 1981 | 1982 | return true; 1983 | } 1984 | 1985 | /* Add item to array/object. */ 1986 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 1987 | { 1988 | return add_item_to_array(array, item); 1989 | } 1990 | 1991 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 1992 | #pragma GCC diagnostic push 1993 | #endif 1994 | #ifdef __GNUC__ 1995 | #pragma GCC diagnostic ignored "-Wcast-qual" 1996 | #endif 1997 | /* helper function to cast away const */ 1998 | static void* cast_away_const(const void* string) 1999 | { 2000 | return (void*)string; 2001 | } 2002 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2003 | #pragma GCC diagnostic pop 2004 | #endif 2005 | 2006 | 2007 | static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) 2008 | { 2009 | char *new_key = NULL; 2010 | int new_type = cJSON_Invalid; 2011 | 2012 | if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2013 | { 2014 | return false; 2015 | } 2016 | 2017 | if (constant_key) 2018 | { 2019 | new_key = (char*)cast_away_const(string); 2020 | new_type = item->type | cJSON_StringIsConst; 2021 | } 2022 | else 2023 | { 2024 | new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2025 | if (new_key == NULL) 2026 | { 2027 | return false; 2028 | } 2029 | 2030 | new_type = item->type & ~cJSON_StringIsConst; 2031 | } 2032 | 2033 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2034 | { 2035 | hooks->deallocate(item->string); 2036 | } 2037 | 2038 | item->string = new_key; 2039 | item->type = new_type; 2040 | 2041 | return add_item_to_array(object, item); 2042 | } 2043 | 2044 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2045 | { 2046 | return add_item_to_object(object, string, item, &global_hooks, false); 2047 | } 2048 | 2049 | /* Add an item to an object with constant string as key */ 2050 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2051 | { 2052 | return add_item_to_object(object, string, item, &global_hooks, true); 2053 | } 2054 | 2055 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2056 | { 2057 | if (array == NULL) 2058 | { 2059 | return false; 2060 | } 2061 | 2062 | return add_item_to_array(array, create_reference(item, &global_hooks)); 2063 | } 2064 | 2065 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2066 | { 2067 | if ((object == NULL) || (string == NULL)) 2068 | { 2069 | return false; 2070 | } 2071 | 2072 | return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2073 | } 2074 | 2075 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2076 | { 2077 | cJSON *null = cJSON_CreateNull(); 2078 | if (add_item_to_object(object, name, null, &global_hooks, false)) 2079 | { 2080 | return null; 2081 | } 2082 | 2083 | cJSON_Delete(null); 2084 | return NULL; 2085 | } 2086 | 2087 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2088 | { 2089 | cJSON *true_item = cJSON_CreateTrue(); 2090 | if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2091 | { 2092 | return true_item; 2093 | } 2094 | 2095 | cJSON_Delete(true_item); 2096 | return NULL; 2097 | } 2098 | 2099 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2100 | { 2101 | cJSON *false_item = cJSON_CreateFalse(); 2102 | if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2103 | { 2104 | return false_item; 2105 | } 2106 | 2107 | cJSON_Delete(false_item); 2108 | return NULL; 2109 | } 2110 | 2111 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2112 | { 2113 | cJSON *bool_item = cJSON_CreateBool(boolean); 2114 | if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2115 | { 2116 | return bool_item; 2117 | } 2118 | 2119 | cJSON_Delete(bool_item); 2120 | return NULL; 2121 | } 2122 | 2123 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2124 | { 2125 | cJSON *number_item = cJSON_CreateNumber(number); 2126 | if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2127 | { 2128 | return number_item; 2129 | } 2130 | 2131 | cJSON_Delete(number_item); 2132 | return NULL; 2133 | } 2134 | 2135 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2136 | { 2137 | cJSON *string_item = cJSON_CreateString(string); 2138 | if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2139 | { 2140 | return string_item; 2141 | } 2142 | 2143 | cJSON_Delete(string_item); 2144 | return NULL; 2145 | } 2146 | 2147 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2148 | { 2149 | cJSON *raw_item = cJSON_CreateRaw(raw); 2150 | if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2151 | { 2152 | return raw_item; 2153 | } 2154 | 2155 | cJSON_Delete(raw_item); 2156 | return NULL; 2157 | } 2158 | 2159 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2160 | { 2161 | cJSON *object_item = cJSON_CreateObject(); 2162 | if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2163 | { 2164 | return object_item; 2165 | } 2166 | 2167 | cJSON_Delete(object_item); 2168 | return NULL; 2169 | } 2170 | 2171 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2172 | { 2173 | cJSON *array = cJSON_CreateArray(); 2174 | if (add_item_to_object(object, name, array, &global_hooks, false)) 2175 | { 2176 | return array; 2177 | } 2178 | 2179 | cJSON_Delete(array); 2180 | return NULL; 2181 | } 2182 | 2183 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2184 | { 2185 | if ((parent == NULL) || (item == NULL)) 2186 | { 2187 | return NULL; 2188 | } 2189 | 2190 | if (item != parent->child) 2191 | { 2192 | /* not the first element */ 2193 | item->prev->next = item->next; 2194 | } 2195 | if (item->next != NULL) 2196 | { 2197 | /* not the last element */ 2198 | item->next->prev = item->prev; 2199 | } 2200 | 2201 | if (item == parent->child) 2202 | { 2203 | /* first element */ 2204 | parent->child = item->next; 2205 | } 2206 | else if (item->next == NULL) 2207 | { 2208 | /* last element */ 2209 | parent->child->prev = item->prev; 2210 | } 2211 | 2212 | /* make sure the detached item doesn't point anywhere anymore */ 2213 | item->prev = NULL; 2214 | item->next = NULL; 2215 | 2216 | return item; 2217 | } 2218 | 2219 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2220 | { 2221 | if (which < 0) 2222 | { 2223 | return NULL; 2224 | } 2225 | 2226 | return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2227 | } 2228 | 2229 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2230 | { 2231 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2232 | } 2233 | 2234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2235 | { 2236 | cJSON *to_detach = cJSON_GetObjectItem(object, string); 2237 | 2238 | return cJSON_DetachItemViaPointer(object, to_detach); 2239 | } 2240 | 2241 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2242 | { 2243 | cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2244 | 2245 | return cJSON_DetachItemViaPointer(object, to_detach); 2246 | } 2247 | 2248 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2249 | { 2250 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2251 | } 2252 | 2253 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2254 | { 2255 | cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2256 | } 2257 | 2258 | /* Replace array/object items with new ones. */ 2259 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2260 | { 2261 | cJSON *after_inserted = NULL; 2262 | 2263 | if (which < 0) 2264 | { 2265 | return false; 2266 | } 2267 | 2268 | after_inserted = get_array_item(array, (size_t)which); 2269 | if (after_inserted == NULL) 2270 | { 2271 | return add_item_to_array(array, newitem); 2272 | } 2273 | 2274 | newitem->next = after_inserted; 2275 | newitem->prev = after_inserted->prev; 2276 | after_inserted->prev = newitem; 2277 | if (after_inserted == array->child) 2278 | { 2279 | array->child = newitem; 2280 | } 2281 | else 2282 | { 2283 | newitem->prev->next = newitem; 2284 | } 2285 | return true; 2286 | } 2287 | 2288 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2289 | { 2290 | if ((parent == NULL) || (replacement == NULL) || (item == NULL)) 2291 | { 2292 | return false; 2293 | } 2294 | 2295 | if (replacement == item) 2296 | { 2297 | return true; 2298 | } 2299 | 2300 | replacement->next = item->next; 2301 | replacement->prev = item->prev; 2302 | 2303 | if (replacement->next != NULL) 2304 | { 2305 | replacement->next->prev = replacement; 2306 | } 2307 | if (parent->child == item) 2308 | { 2309 | if (parent->child->prev == parent->child) 2310 | { 2311 | replacement->prev = replacement; 2312 | } 2313 | parent->child = replacement; 2314 | } 2315 | else 2316 | { /* 2317 | * To find the last item in array quickly, we use prev in array. 2318 | * We can't modify the last item's next pointer where this item was the parent's child 2319 | */ 2320 | if (replacement->prev != NULL) 2321 | { 2322 | replacement->prev->next = replacement; 2323 | } 2324 | if (replacement->next == NULL) 2325 | { 2326 | parent->child->prev = replacement; 2327 | } 2328 | } 2329 | 2330 | item->next = NULL; 2331 | item->prev = NULL; 2332 | cJSON_Delete(item); 2333 | 2334 | return true; 2335 | } 2336 | 2337 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2338 | { 2339 | if (which < 0) 2340 | { 2341 | return false; 2342 | } 2343 | 2344 | return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2345 | } 2346 | 2347 | static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2348 | { 2349 | if ((replacement == NULL) || (string == NULL)) 2350 | { 2351 | return false; 2352 | } 2353 | 2354 | /* replace the name in the replacement */ 2355 | if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2356 | { 2357 | cJSON_free(replacement->string); 2358 | } 2359 | replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2360 | replacement->type &= ~cJSON_StringIsConst; 2361 | 2362 | return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2363 | } 2364 | 2365 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2366 | { 2367 | return replace_item_in_object(object, string, newitem, false); 2368 | } 2369 | 2370 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2371 | { 2372 | return replace_item_in_object(object, string, newitem, true); 2373 | } 2374 | 2375 | /* Create basic types: */ 2376 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2377 | { 2378 | cJSON *item = cJSON_New_Item(&global_hooks); 2379 | if(item) 2380 | { 2381 | item->type = cJSON_NULL; 2382 | } 2383 | 2384 | return item; 2385 | } 2386 | 2387 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2388 | { 2389 | cJSON *item = cJSON_New_Item(&global_hooks); 2390 | if(item) 2391 | { 2392 | item->type = cJSON_True; 2393 | } 2394 | 2395 | return item; 2396 | } 2397 | 2398 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2399 | { 2400 | cJSON *item = cJSON_New_Item(&global_hooks); 2401 | if(item) 2402 | { 2403 | item->type = cJSON_False; 2404 | } 2405 | 2406 | return item; 2407 | } 2408 | 2409 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2410 | { 2411 | cJSON *item = cJSON_New_Item(&global_hooks); 2412 | if(item) 2413 | { 2414 | item->type = boolean ? cJSON_True : cJSON_False; 2415 | } 2416 | 2417 | return item; 2418 | } 2419 | 2420 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2421 | { 2422 | cJSON *item = cJSON_New_Item(&global_hooks); 2423 | if(item) 2424 | { 2425 | item->type = cJSON_Number; 2426 | item->valuedouble = num; 2427 | 2428 | /* use saturation in case of overflow */ 2429 | if (num >= INT_MAX) 2430 | { 2431 | item->valueint = INT_MAX; 2432 | } 2433 | else if (num <= (double)INT_MIN) 2434 | { 2435 | item->valueint = INT_MIN; 2436 | } 2437 | else 2438 | { 2439 | item->valueint = (int)num; 2440 | } 2441 | } 2442 | 2443 | return item; 2444 | } 2445 | 2446 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2447 | { 2448 | cJSON *item = cJSON_New_Item(&global_hooks); 2449 | if(item) 2450 | { 2451 | item->type = cJSON_String; 2452 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2453 | if(!item->valuestring) 2454 | { 2455 | cJSON_Delete(item); 2456 | return NULL; 2457 | } 2458 | } 2459 | 2460 | return item; 2461 | } 2462 | 2463 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2464 | { 2465 | cJSON *item = cJSON_New_Item(&global_hooks); 2466 | if (item != NULL) 2467 | { 2468 | item->type = cJSON_String | cJSON_IsReference; 2469 | item->valuestring = (char*)cast_away_const(string); 2470 | } 2471 | 2472 | return item; 2473 | } 2474 | 2475 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2476 | { 2477 | cJSON *item = cJSON_New_Item(&global_hooks); 2478 | if (item != NULL) { 2479 | item->type = cJSON_Object | cJSON_IsReference; 2480 | item->child = (cJSON*)cast_away_const(child); 2481 | } 2482 | 2483 | return item; 2484 | } 2485 | 2486 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2487 | cJSON *item = cJSON_New_Item(&global_hooks); 2488 | if (item != NULL) { 2489 | item->type = cJSON_Array | cJSON_IsReference; 2490 | item->child = (cJSON*)cast_away_const(child); 2491 | } 2492 | 2493 | return item; 2494 | } 2495 | 2496 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2497 | { 2498 | cJSON *item = cJSON_New_Item(&global_hooks); 2499 | if(item) 2500 | { 2501 | item->type = cJSON_Raw; 2502 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2503 | if(!item->valuestring) 2504 | { 2505 | cJSON_Delete(item); 2506 | return NULL; 2507 | } 2508 | } 2509 | 2510 | return item; 2511 | } 2512 | 2513 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2514 | { 2515 | cJSON *item = cJSON_New_Item(&global_hooks); 2516 | if(item) 2517 | { 2518 | item->type=cJSON_Array; 2519 | } 2520 | 2521 | return item; 2522 | } 2523 | 2524 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2525 | { 2526 | cJSON *item = cJSON_New_Item(&global_hooks); 2527 | if (item) 2528 | { 2529 | item->type = cJSON_Object; 2530 | } 2531 | 2532 | return item; 2533 | } 2534 | 2535 | /* Create Arrays: */ 2536 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2537 | { 2538 | size_t i = 0; 2539 | cJSON *n = NULL; 2540 | cJSON *p = NULL; 2541 | cJSON *a = NULL; 2542 | 2543 | if ((count < 0) || (numbers == NULL)) 2544 | { 2545 | return NULL; 2546 | } 2547 | 2548 | a = cJSON_CreateArray(); 2549 | 2550 | for(i = 0; a && (i < (size_t)count); i++) 2551 | { 2552 | n = cJSON_CreateNumber(numbers[i]); 2553 | if (!n) 2554 | { 2555 | cJSON_Delete(a); 2556 | return NULL; 2557 | } 2558 | if(!i) 2559 | { 2560 | a->child = n; 2561 | } 2562 | else 2563 | { 2564 | suffix_object(p, n); 2565 | } 2566 | p = n; 2567 | } 2568 | 2569 | if (a && a->child) { 2570 | a->child->prev = n; 2571 | } 2572 | 2573 | return a; 2574 | } 2575 | 2576 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2577 | { 2578 | size_t i = 0; 2579 | cJSON *n = NULL; 2580 | cJSON *p = NULL; 2581 | cJSON *a = NULL; 2582 | 2583 | if ((count < 0) || (numbers == NULL)) 2584 | { 2585 | return NULL; 2586 | } 2587 | 2588 | a = cJSON_CreateArray(); 2589 | 2590 | for(i = 0; a && (i < (size_t)count); i++) 2591 | { 2592 | n = cJSON_CreateNumber((double)numbers[i]); 2593 | if(!n) 2594 | { 2595 | cJSON_Delete(a); 2596 | return NULL; 2597 | } 2598 | if(!i) 2599 | { 2600 | a->child = n; 2601 | } 2602 | else 2603 | { 2604 | suffix_object(p, n); 2605 | } 2606 | p = n; 2607 | } 2608 | 2609 | if (a && a->child) { 2610 | a->child->prev = n; 2611 | } 2612 | 2613 | return a; 2614 | } 2615 | 2616 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2617 | { 2618 | size_t i = 0; 2619 | cJSON *n = NULL; 2620 | cJSON *p = NULL; 2621 | cJSON *a = NULL; 2622 | 2623 | if ((count < 0) || (numbers == NULL)) 2624 | { 2625 | return NULL; 2626 | } 2627 | 2628 | a = cJSON_CreateArray(); 2629 | 2630 | for(i = 0; a && (i < (size_t)count); i++) 2631 | { 2632 | n = cJSON_CreateNumber(numbers[i]); 2633 | if(!n) 2634 | { 2635 | cJSON_Delete(a); 2636 | return NULL; 2637 | } 2638 | if(!i) 2639 | { 2640 | a->child = n; 2641 | } 2642 | else 2643 | { 2644 | suffix_object(p, n); 2645 | } 2646 | p = n; 2647 | } 2648 | 2649 | if (a && a->child) { 2650 | a->child->prev = n; 2651 | } 2652 | 2653 | return a; 2654 | } 2655 | 2656 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2657 | { 2658 | size_t i = 0; 2659 | cJSON *n = NULL; 2660 | cJSON *p = NULL; 2661 | cJSON *a = NULL; 2662 | 2663 | if ((count < 0) || (strings == NULL)) 2664 | { 2665 | return NULL; 2666 | } 2667 | 2668 | a = cJSON_CreateArray(); 2669 | 2670 | for (i = 0; a && (i < (size_t)count); i++) 2671 | { 2672 | n = cJSON_CreateString(strings[i]); 2673 | if(!n) 2674 | { 2675 | cJSON_Delete(a); 2676 | return NULL; 2677 | } 2678 | if(!i) 2679 | { 2680 | a->child = n; 2681 | } 2682 | else 2683 | { 2684 | suffix_object(p,n); 2685 | } 2686 | p = n; 2687 | } 2688 | 2689 | if (a && a->child) { 2690 | a->child->prev = n; 2691 | } 2692 | 2693 | return a; 2694 | } 2695 | 2696 | /* Duplication */ 2697 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2698 | { 2699 | cJSON *newitem = NULL; 2700 | cJSON *child = NULL; 2701 | cJSON *next = NULL; 2702 | cJSON *newchild = NULL; 2703 | 2704 | /* Bail on bad ptr */ 2705 | if (!item) 2706 | { 2707 | goto fail; 2708 | } 2709 | /* Create new item */ 2710 | newitem = cJSON_New_Item(&global_hooks); 2711 | if (!newitem) 2712 | { 2713 | goto fail; 2714 | } 2715 | /* Copy over all vars */ 2716 | newitem->type = item->type & (~cJSON_IsReference); 2717 | newitem->valueint = item->valueint; 2718 | newitem->valuedouble = item->valuedouble; 2719 | if (item->valuestring) 2720 | { 2721 | newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2722 | if (!newitem->valuestring) 2723 | { 2724 | goto fail; 2725 | } 2726 | } 2727 | if (item->string) 2728 | { 2729 | newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2730 | if (!newitem->string) 2731 | { 2732 | goto fail; 2733 | } 2734 | } 2735 | /* If non-recursive, then we're done! */ 2736 | if (!recurse) 2737 | { 2738 | return newitem; 2739 | } 2740 | /* Walk the ->next chain for the child. */ 2741 | child = item->child; 2742 | while (child != NULL) 2743 | { 2744 | newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2745 | if (!newchild) 2746 | { 2747 | goto fail; 2748 | } 2749 | if (next != NULL) 2750 | { 2751 | /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2752 | next->next = newchild; 2753 | newchild->prev = next; 2754 | next = newchild; 2755 | } 2756 | else 2757 | { 2758 | /* Set newitem->child and move to it */ 2759 | newitem->child = newchild; 2760 | next = newchild; 2761 | } 2762 | child = child->next; 2763 | } 2764 | if (newitem && newitem->child) 2765 | { 2766 | newitem->child->prev = newchild; 2767 | } 2768 | 2769 | return newitem; 2770 | 2771 | fail: 2772 | if (newitem != NULL) 2773 | { 2774 | cJSON_Delete(newitem); 2775 | } 2776 | 2777 | return NULL; 2778 | } 2779 | 2780 | static void skip_oneline_comment(char **input) 2781 | { 2782 | *input += static_strlen("//"); 2783 | 2784 | for (; (*input)[0] != '\0'; ++(*input)) 2785 | { 2786 | if ((*input)[0] == '\n') { 2787 | *input += static_strlen("\n"); 2788 | return; 2789 | } 2790 | } 2791 | } 2792 | 2793 | static void skip_multiline_comment(char **input) 2794 | { 2795 | *input += static_strlen("/*"); 2796 | 2797 | for (; (*input)[0] != '\0'; ++(*input)) 2798 | { 2799 | if (((*input)[0] == '*') && ((*input)[1] == '/')) 2800 | { 2801 | *input += static_strlen("*/"); 2802 | return; 2803 | } 2804 | } 2805 | } 2806 | 2807 | static void minify_string(char **input, char **output) { 2808 | (*output)[0] = (*input)[0]; 2809 | *input += static_strlen("\""); 2810 | *output += static_strlen("\""); 2811 | 2812 | 2813 | for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2814 | (*output)[0] = (*input)[0]; 2815 | 2816 | if ((*input)[0] == '\"') { 2817 | (*output)[0] = '\"'; 2818 | *input += static_strlen("\""); 2819 | *output += static_strlen("\""); 2820 | return; 2821 | } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2822 | (*output)[1] = (*input)[1]; 2823 | *input += static_strlen("\""); 2824 | *output += static_strlen("\""); 2825 | } 2826 | } 2827 | } 2828 | 2829 | CJSON_PUBLIC(void) cJSON_Minify(char *json) 2830 | { 2831 | char *into = json; 2832 | 2833 | if (json == NULL) 2834 | { 2835 | return; 2836 | } 2837 | 2838 | while (json[0] != '\0') 2839 | { 2840 | switch (json[0]) 2841 | { 2842 | case ' ': 2843 | case '\t': 2844 | case '\r': 2845 | case '\n': 2846 | json++; 2847 | break; 2848 | 2849 | case '/': 2850 | if (json[1] == '/') 2851 | { 2852 | skip_oneline_comment(&json); 2853 | } 2854 | else if (json[1] == '*') 2855 | { 2856 | skip_multiline_comment(&json); 2857 | } else { 2858 | json++; 2859 | } 2860 | break; 2861 | 2862 | case '\"': 2863 | minify_string(&json, (char**)&into); 2864 | break; 2865 | 2866 | default: 2867 | into[0] = json[0]; 2868 | json++; 2869 | into++; 2870 | } 2871 | } 2872 | 2873 | /* and null-terminate. */ 2874 | *into = '\0'; 2875 | } 2876 | 2877 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2878 | { 2879 | if (item == NULL) 2880 | { 2881 | return false; 2882 | } 2883 | 2884 | return (item->type & 0xFF) == cJSON_Invalid; 2885 | } 2886 | 2887 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2888 | { 2889 | if (item == NULL) 2890 | { 2891 | return false; 2892 | } 2893 | 2894 | return (item->type & 0xFF) == cJSON_False; 2895 | } 2896 | 2897 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2898 | { 2899 | if (item == NULL) 2900 | { 2901 | return false; 2902 | } 2903 | 2904 | return (item->type & 0xff) == cJSON_True; 2905 | } 2906 | 2907 | 2908 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2909 | { 2910 | if (item == NULL) 2911 | { 2912 | return false; 2913 | } 2914 | 2915 | return (item->type & (cJSON_True | cJSON_False)) != 0; 2916 | } 2917 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2918 | { 2919 | if (item == NULL) 2920 | { 2921 | return false; 2922 | } 2923 | 2924 | return (item->type & 0xFF) == cJSON_NULL; 2925 | } 2926 | 2927 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2928 | { 2929 | if (item == NULL) 2930 | { 2931 | return false; 2932 | } 2933 | 2934 | return (item->type & 0xFF) == cJSON_Number; 2935 | } 2936 | 2937 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2938 | { 2939 | if (item == NULL) 2940 | { 2941 | return false; 2942 | } 2943 | 2944 | return (item->type & 0xFF) == cJSON_String; 2945 | } 2946 | 2947 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2948 | { 2949 | if (item == NULL) 2950 | { 2951 | return false; 2952 | } 2953 | 2954 | return (item->type & 0xFF) == cJSON_Array; 2955 | } 2956 | 2957 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2958 | { 2959 | if (item == NULL) 2960 | { 2961 | return false; 2962 | } 2963 | 2964 | return (item->type & 0xFF) == cJSON_Object; 2965 | } 2966 | 2967 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 2968 | { 2969 | if (item == NULL) 2970 | { 2971 | return false; 2972 | } 2973 | 2974 | return (item->type & 0xFF) == cJSON_Raw; 2975 | } 2976 | 2977 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 2978 | { 2979 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) 2980 | { 2981 | return false; 2982 | } 2983 | 2984 | /* check if type is valid */ 2985 | switch (a->type & 0xFF) 2986 | { 2987 | case cJSON_False: 2988 | case cJSON_True: 2989 | case cJSON_NULL: 2990 | case cJSON_Number: 2991 | case cJSON_String: 2992 | case cJSON_Raw: 2993 | case cJSON_Array: 2994 | case cJSON_Object: 2995 | break; 2996 | 2997 | default: 2998 | return false; 2999 | } 3000 | 3001 | /* identical objects are equal */ 3002 | if (a == b) 3003 | { 3004 | return true; 3005 | } 3006 | 3007 | switch (a->type & 0xFF) 3008 | { 3009 | /* in these cases and equal type is enough */ 3010 | case cJSON_False: 3011 | case cJSON_True: 3012 | case cJSON_NULL: 3013 | return true; 3014 | 3015 | case cJSON_Number: 3016 | if (compare_double(a->valuedouble, b->valuedouble)) 3017 | { 3018 | return true; 3019 | } 3020 | return false; 3021 | 3022 | case cJSON_String: 3023 | case cJSON_Raw: 3024 | if ((a->valuestring == NULL) || (b->valuestring == NULL)) 3025 | { 3026 | return false; 3027 | } 3028 | if (strcmp(a->valuestring, b->valuestring) == 0) 3029 | { 3030 | return true; 3031 | } 3032 | 3033 | return false; 3034 | 3035 | case cJSON_Array: 3036 | { 3037 | cJSON *a_element = a->child; 3038 | cJSON *b_element = b->child; 3039 | 3040 | for (; (a_element != NULL) && (b_element != NULL);) 3041 | { 3042 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3043 | { 3044 | return false; 3045 | } 3046 | 3047 | a_element = a_element->next; 3048 | b_element = b_element->next; 3049 | } 3050 | 3051 | /* one of the arrays is longer than the other */ 3052 | if (a_element != b_element) { 3053 | return false; 3054 | } 3055 | 3056 | return true; 3057 | } 3058 | 3059 | case cJSON_Object: 3060 | { 3061 | cJSON *a_element = NULL; 3062 | cJSON *b_element = NULL; 3063 | cJSON_ArrayForEach(a_element, a) 3064 | { 3065 | /* TODO This has O(n^2) runtime, which is horrible! */ 3066 | b_element = get_object_item(b, a_element->string, case_sensitive); 3067 | if (b_element == NULL) 3068 | { 3069 | return false; 3070 | } 3071 | 3072 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3073 | { 3074 | return false; 3075 | } 3076 | } 3077 | 3078 | /* doing this twice, once on a and b to prevent true comparison if a subset of b 3079 | * TODO: Do this the proper way, this is just a fix for now */ 3080 | cJSON_ArrayForEach(b_element, b) 3081 | { 3082 | a_element = get_object_item(a, b_element->string, case_sensitive); 3083 | if (a_element == NULL) 3084 | { 3085 | return false; 3086 | } 3087 | 3088 | if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3089 | { 3090 | return false; 3091 | } 3092 | } 3093 | 3094 | return true; 3095 | } 3096 | 3097 | default: 3098 | return false; 3099 | } 3100 | } 3101 | 3102 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3103 | { 3104 | return global_hooks.allocate(size); 3105 | } 3106 | 3107 | CJSON_PUBLIC(void) cJSON_free(void *object) 3108 | { 3109 | global_hooks.deallocate(object); 3110 | } 3111 | -------------------------------------------------------------------------------- /src/parser/json.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: 38 | 39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 42 | 43 | For *nix builds that support visibility attribute, you can define similar behavior by 44 | 45 | setting default visibility to hidden by adding 46 | -fvisibility=hidden (for gcc) 47 | or 48 | -xldscope=hidden (for sun cc) 49 | to CFLAGS 50 | 51 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 52 | 53 | */ 54 | 55 | #define CJSON_CDECL __cdecl 56 | #define CJSON_STDCALL __stdcall 57 | 58 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 59 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 60 | #define CJSON_EXPORT_SYMBOLS 61 | #endif 62 | 63 | #if defined(CJSON_HIDE_SYMBOLS) 64 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 65 | #elif defined(CJSON_EXPORT_SYMBOLS) 66 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 67 | #elif defined(CJSON_IMPORT_SYMBOLS) 68 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 69 | #endif 70 | #else /* !__WINDOWS__ */ 71 | #define CJSON_CDECL 72 | #define CJSON_STDCALL 73 | 74 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 75 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 76 | #else 77 | #define CJSON_PUBLIC(type) type 78 | #endif 79 | #endif 80 | 81 | /* project version */ 82 | #define CJSON_VERSION_MAJOR 1 83 | #define CJSON_VERSION_MINOR 7 84 | #define CJSON_VERSION_PATCH 15 85 | 86 | #include 87 | 88 | /* cJSON Types: */ 89 | #define cJSON_Invalid (0) 90 | #define cJSON_False (1 << 0) 91 | #define cJSON_True (1 << 1) 92 | #define cJSON_NULL (1 << 2) 93 | #define cJSON_Number (1 << 3) 94 | #define cJSON_String (1 << 4) 95 | #define cJSON_Array (1 << 5) 96 | #define cJSON_Object (1 << 6) 97 | #define cJSON_Raw (1 << 7) /* raw json */ 98 | 99 | #define cJSON_IsReference 256 100 | #define cJSON_StringIsConst 512 101 | 102 | /* The cJSON structure: */ 103 | typedef struct cJSON 104 | { 105 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 106 | struct cJSON *next; 107 | struct cJSON *prev; 108 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 109 | struct cJSON *child; 110 | 111 | /* The type of the item, as above. */ 112 | int type; 113 | 114 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 115 | char *valuestring; 116 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 117 | int valueint; 118 | /* The item's number, if type==cJSON_Number */ 119 | double valuedouble; 120 | 121 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 122 | char *string; 123 | } cJSON; 124 | 125 | typedef struct cJSON_Hooks 126 | { 127 | /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ 128 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 129 | void (CJSON_CDECL *free_fn)(void *ptr); 130 | } cJSON_Hooks; 131 | 132 | typedef int cJSON_bool; 133 | 134 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 135 | * This is to prevent stack overflows. */ 136 | #ifndef CJSON_NESTING_LIMIT 137 | #define CJSON_NESTING_LIMIT 1000 138 | #endif 139 | 140 | /* returns the version of cJSON as a string */ 141 | CJSON_PUBLIC(const char*) cJSON_Version(void); 142 | 143 | /* Supply malloc, realloc and free functions to cJSON */ 144 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 145 | 146 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 147 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 148 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 149 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); 150 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 151 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ 152 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 153 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); 154 | 155 | /* Render a cJSON entity to text for transfer/storage. */ 156 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 157 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 158 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 159 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 160 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 161 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 162 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 163 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 164 | /* Delete a cJSON entity and all subentities. */ 165 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 166 | 167 | /* Returns the number of items in an array (or object). */ 168 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 169 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ 170 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 171 | /* Get item "string" from object. Case insensitive. */ 172 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 173 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 175 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 176 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 177 | 178 | /* Check item type and return its value */ 179 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); 181 | 182 | /* These functions check the type of an item */ 183 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 184 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 185 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 186 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 187 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 188 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 193 | 194 | /* These calls create a cJSON item of the appropriate type. */ 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 197 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 198 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 199 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 200 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 201 | /* raw json */ 202 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 203 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 204 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 205 | 206 | /* Create a string where valuestring references a string so 207 | * it will not be freed by cJSON_Delete */ 208 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 209 | /* Create an object/array that only references it's elements so 210 | * they will not be freed by cJSON_Delete */ 211 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 212 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 213 | 214 | /* These utilities create an Array of count items. 215 | * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ 216 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 217 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 218 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 219 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); 220 | 221 | /* Append item to the specified array/object. */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 224 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 225 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 226 | * writing to `item->string` */ 227 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 228 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 229 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 231 | 232 | /* Remove/Detach items from Arrays/Objects. */ 233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 235 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 236 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 237 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 238 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 239 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 240 | 241 | /* Update array items. */ 242 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 243 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 244 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 245 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 246 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 247 | 248 | /* Duplicate a cJSON item */ 249 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 250 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 251 | * need to be released. With recurse!=0, it will duplicate any children connected to the item. 252 | * The item->next and ->prev pointers are always zero on return from Duplicate. */ 253 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 254 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 255 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 256 | 257 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. 258 | * The input pointer json cannot point to a read-only address area, such as a string constant, 259 | * but should point to a readable and writable address area. */ 260 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 261 | 262 | /* Helper functions for creating and adding items to an object at the same time. 263 | * They return the added item or NULL on failure. */ 264 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); 265 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); 266 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); 267 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); 268 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); 269 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); 270 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); 271 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); 272 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); 273 | 274 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 275 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 276 | /* helper for the cJSON_SetNumberValue macro */ 277 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 278 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 279 | /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ 280 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); 281 | 282 | /* Macro for iterating over an array or object */ 283 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 284 | 285 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 286 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 287 | CJSON_PUBLIC(void) cJSON_free(void *object); 288 | 289 | #ifdef __cplusplus 290 | } 291 | #endif 292 | 293 | #endif 294 | -------------------------------------------------------------------------------- /src/parser/regex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* This is POSIX regex.h */ 3 | #include 4 | 5 | #include "regex.h" /* This is the wrapper */ 6 | #include "../common.h" 7 | 8 | struct RegexResults *regex_findall(char *buffer, char *pattern) 9 | { 10 | regex_t regex; 11 | regoff_t offset = 0; 12 | regmatch_t pmatch[2]; 13 | static struct RegexResults results = { 0 }; 14 | 15 | if (regcomp(®ex, pattern, REG_NEWLINE | REG_EXTENDED)) 16 | die("regcomp: Cannot compile regex"); 17 | 18 | int i; 19 | unsigned int length; 20 | regmatch_t substr_pos = { 0 }; 21 | for (i = 0; i < MAX_REGEX_MATCHES; i++) { 22 | if (regexec(®ex, buffer + offset, ARRAY_SIZE(pmatch), pmatch, 0)) 23 | break; 24 | 25 | substr_pos.rm_so = pmatch[1].rm_so + offset; 26 | substr_pos.rm_eo = pmatch[1].rm_eo + offset; 27 | length = substr_pos.rm_eo - substr_pos.rm_so; 28 | 29 | strncpy(results.matches[i], buffer + substr_pos.rm_so, length); 30 | results.matches[i][length] = '\0'; 31 | 32 | offset += pmatch[1].rm_eo; 33 | } 34 | 35 | results.count = i; 36 | 37 | regfree(®ex); 38 | return &results; 39 | } 40 | 41 | char *regex_find(char *buffer, char *pattern) 42 | { 43 | /* Return the first match */ 44 | return regex_findall(buffer, pattern)->matches[0]; 45 | } 46 | -------------------------------------------------------------------------------- /src/parser/regex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a wrapper around the POSIX regex.h 3 | */ 4 | 5 | #ifndef CANIME_PARSER_H 6 | #define CANIME_PARSER_H 7 | 8 | #define MAX_REGEX_MATCHES 16 9 | #define MAX_REGEX_MATCH_SIZE 256 10 | 11 | struct RegexResults { 12 | unsigned int count; 13 | char matches[MAX_REGEX_MATCHES][MAX_REGEX_MATCH_SIZE]; 14 | }; 15 | 16 | // Find the first occurrence of pattern in buffer 17 | char *regex_find(char *buffer, char *pattern); 18 | 19 | // Find MAX_REGEX_MATCHES occurences of pattern in buffer 20 | struct RegexResults *regex_findall(char *buffer, char *pattern); 21 | 22 | #endif /* CANIME_PARSER_H */ 23 | -------------------------------------------------------------------------------- /src/provider.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "provider.h" 4 | #include "common.h" 5 | #include "sites/sites.h" 6 | 7 | struct AnimeProvider *get_anime_provider(char *name) 8 | { 9 | static struct AnimeProvider providers[] = { 10 | { "gogoanime", gogoanime_search, gogoanime_get_metadata, gogoanime_get_sources }, 11 | { "animepahe", animepahe_search, animepahe_get_metadata, animepahe_get_sources }, 12 | }; 13 | 14 | for (unsigned int i = 0; i < ARRAY_SIZE(providers); i++) { 15 | if (strcmp(name, providers[i].name) == 0) { 16 | return &providers[i]; 17 | } 18 | } 19 | 20 | return NULL; 21 | } 22 | -------------------------------------------------------------------------------- /src/provider.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_PROVIDER_H 2 | #define CANIME_PROVIDER_H 3 | 4 | #include "anime.h" 5 | 6 | struct AnimeProvider { 7 | char *name; 8 | struct SearchResults *(*search)(char *query); 9 | struct AnimeInfo *(*get_metadata)(char *anime_id); 10 | void (*get_sources)(struct AnimeInfo *anime); 11 | }; 12 | 13 | // Get the anime provider 14 | struct AnimeProvider *get_anime_provider(char *name); 15 | 16 | #endif /* CANIME_PROVIDER_H */ 17 | -------------------------------------------------------------------------------- /src/sites/animepahe.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include "animepahe.h" 3 | 4 | #include "../parser/json.h" 5 | 6 | static char *web_page; 7 | 8 | // ----------------------------------------------------------------------------- 9 | // AnimePahe 10 | // ----------------------------------------------------------------------------- 11 | struct SearchResults *animepahe_search(char *query) 12 | { 13 | static struct SearchResults results; 14 | 15 | web_client_seturl("https://animepahe.com/api?l=8&m=search", NULL); 16 | web_client_setpayload("q", query); 17 | web_page = web_client_perform(); 18 | 19 | return &results; 20 | } 21 | 22 | struct AnimeInfo *animepahe_get_metadata(char *animeid) 23 | { 24 | struct AnimeInfo *metadata = xmalloc(sizeof(struct AnimeInfo)); 25 | 26 | return metadata; 27 | } 28 | 29 | void animepahe_get_sources(struct AnimeInfo *anime) 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /src/sites/animepahe.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_SITES_ANIMEPAHE_H 2 | #define CANIME_SITES_ANIMEPAHE_H 3 | 4 | struct SearchResults *animepahe_search(char *query); 5 | struct AnimeInfo *animepahe_get_metadata(char *animeid); 6 | void animepahe_get_sources(struct AnimeInfo *anime); 7 | 8 | #endif /* CANIME_SITES_ANIMEPAHE_H */ 9 | -------------------------------------------------------------------------------- /src/sites/base.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_SITES_BASE_H 2 | #define CANIME_SITES_BASE_H 3 | 4 | #include "../anime.h" 5 | #include "../utils.h" 6 | #include "../common.h" 7 | #include "../web_client.h" 8 | 9 | #endif /* CANIME_SITES_BASE_H */ 10 | -------------------------------------------------------------------------------- /src/sites/gogoanime.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "base.h" 5 | #include "gogoanime.h" 6 | #include "../parser/regex.h" 7 | 8 | #define BASE_URL "https://gogoanime.cm/" 9 | 10 | static char *web_page; 11 | 12 | // ----------------------------------------------------------------------------- 13 | // GogoAnime 14 | // ----------------------------------------------------------------------------- 15 | struct SearchResults *gogoanime_search(char *query) 16 | { 17 | struct RegexResults *regex_results; 18 | static struct SearchResults results; 19 | 20 | web_client_seturl(BASE_URL "/search.html", NULL); 21 | web_client_setpayload("keyword", query); 22 | 23 | web_page = web_client_perform(); 24 | 25 | regex_results = regex_findall(web_page, 26 | "

count; 29 | for (int i = 0; i < MAX_ANIME_SEARCH_RESULTS; i++) { 30 | memcpy(results.results[i], regex_results->matches[i], 31 | MAX_ANIME_NAME_LEN); 32 | } 33 | 34 | return &results; 35 | } 36 | 37 | struct AnimeInfo *gogoanime_get_metadata(char *animeid) 38 | { 39 | int last_episode_num; 40 | char *last_episode_str; 41 | struct AnimeInfo *metadata = malloc(sizeof(struct AnimeInfo)); 42 | 43 | char *url = JOIN_STR(BASE_URL "/category/", animeid, NULL); 44 | 45 | web_client_seturl(url, NULL); 46 | web_page = web_client_perform(); 47 | 48 | last_episode_str = regex_find(web_page, 49 | ".*.*"); 50 | 51 | last_episode_num = strtol(last_episode_str, NULL, 10); 52 | 53 | metadata->title = animeid; 54 | metadata->current_episode = 0; 55 | metadata->total_episodes = last_episode_num; 56 | 57 | return metadata; 58 | } 59 | 60 | void gogoanime_get_sources(struct AnimeInfo *anime) 61 | { 62 | char *video_url, *highq_video, *video_url_end, *embedded_video_url; 63 | unsigned int highq_video_len; 64 | 65 | char *url = JOIN_STR(BASE_URL, anime->title, "-episode-", int2str(anime->current_episode)); 66 | 67 | web_client_seturl(url, NULL); 68 | web_page = web_client_perform(); 69 | 70 | embedded_video_url = regex_find(web_page, 71 | "^[[:space:]]*.*"); 72 | 73 | /* The resulting URL doesn't have `https:` part */ 74 | embedded_video_url = JOIN_STR("https:", embedded_video_url); 75 | 76 | web_client_seturl(embedded_video_url, NULL); 77 | web_page = web_client_perform(); 78 | video_url = regex_find(web_page, 79 | "^[[:space:]]*sources:\\[\\{file: '([^']*)'.*"); 80 | 81 | web_client_seturl(video_url, embedded_video_url); 82 | web_page = web_client_perform(); 83 | highq_video = get_lastline(web_page); 84 | 85 | // Copy referer and url to the result 86 | strncpy(anime->episode.referer, embedded_video_url, sizeof(anime->episode.referer) - 1); 87 | anime->episode.referer[sizeof(anime->episode.referer) - 1] = '\0'; 88 | 89 | strncpy(anime->episode.url, video_url, 90 | sizeof(anime->episode.url) - 1); 91 | 92 | // Get the file name part from the video url 93 | video_url_end = strrchr(anime->episode.url, '/') + 1; 94 | highq_video_len = strlen(highq_video); 95 | 96 | // Replace the filename with highq_video 97 | // Also remove the pesky newline character at the end 98 | memcpy(video_url_end, highq_video, highq_video_len - 1); 99 | video_url_end[highq_video_len - 1] = '\0'; 100 | } 101 | -------------------------------------------------------------------------------- /src/sites/gogoanime.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_SITES_GOGOANIME_H 2 | #define CANIME_SITES_GOGOANIME_H 3 | 4 | struct SearchResults *gogoanime_search(char *query); 5 | struct AnimeInfo *gogoanime_get_metadata(char *animeid); 6 | void gogoanime_get_sources(struct AnimeInfo *anime); 7 | 8 | #endif /* CANIME_SITES_GOGOANIME_H */ 9 | -------------------------------------------------------------------------------- /src/sites/sites.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_SITES_H 2 | #define CANIME_SITES_H 3 | 4 | #include "gogoanime.h" 5 | #include "animepahe.h" 6 | 7 | #endif /* CANIME_SITES_H */ 8 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "utils.h" 8 | #include "common.h" 9 | #include "anime.h" 10 | 11 | #define INT2STR_SIZE 12 12 | 13 | char *int2str(int number) 14 | { 15 | static char result[INT2STR_SIZE]; 16 | snprintf(result, sizeof(result), "%d", number); 17 | 18 | return result; 19 | } 20 | 21 | char *get_lastline(char *str) 22 | { 23 | bool line_found = false; 24 | size_t length = strlen(str); 25 | 26 | // Reverse string 27 | for (char *ptr = str + length - 1; ptr > str; ptr--) { 28 | if (*ptr != '\n') { 29 | line_found = true; 30 | continue; 31 | } 32 | 33 | if (line_found) 34 | return ptr + 1; 35 | } 36 | 37 | return NULL; 38 | } 39 | 40 | void play_episode(struct AnimeInfo *anime) 41 | { 42 | if (fork() == 0) { 43 | setsid(); 44 | 45 | // Set the referer 46 | char *args = "--http-header-fields=Referer: "; 47 | char header_fields[strlen(args) + URL_BUF_SIZE]; 48 | snprintf(header_fields, sizeof(header_fields), 49 | "%s%s", args, anime->episode.referer); 50 | 51 | char *command[] = { "mpv", "--really-quiet", header_fields, 52 | anime->episode.url, NULL }; 53 | 54 | // execute mpv 55 | execvp(command[0], command); 56 | 57 | // If it got here, it's an error 58 | die("canime: execvp %s failed %s", command[0], strerror(errno)); 59 | } 60 | } 61 | 62 | char *join_str(char **str_list) 63 | { 64 | static char result[MAX_TEXT_BUFFER_SIZE]; 65 | memset(result, 0, MAX_TEXT_BUFFER_SIZE); 66 | 67 | for (char **ptr = str_list; *ptr != NULL; ptr++) { 68 | strncat(result, *ptr, MAX_TEXT_BUFFER_SIZE - strlen(result) - 1); 69 | } 70 | 71 | return result; 72 | } 73 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_UTILS_H 2 | #define CANIME_UTILS_H 3 | 4 | #define MAX_TEXT_BUFFER_SIZE 256 5 | #define JOIN_STR(...) join_str((char *[]){ __VA_ARGS__, NULL }) 6 | 7 | struct AnimeInfo; 8 | 9 | // Convert int to string 10 | char *int2str(int number); 11 | 12 | // Get pointer to last line of string 13 | char *get_lastline(char *str); 14 | 15 | // Join strings. Be sure to free() it 16 | char *join_str(char **str_list); 17 | 18 | // Play the anime 19 | void play_episode(struct AnimeInfo *metadata); 20 | 21 | #endif /* CANIME_UTILS_H */ 22 | -------------------------------------------------------------------------------- /src/web_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "web_client.h" 6 | #include "common.h" 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Structure Defintions 10 | // ---------------------------------------------------------------------------- 11 | struct WebPage { 12 | char *buffer; 13 | size_t size; 14 | }; 15 | 16 | static struct WebClient { 17 | CURL *handle; 18 | char url[URL_BUF_SIZE]; 19 | struct WebPage webpage; 20 | } *self; 21 | 22 | // ---------------------------------------------------------------------------- 23 | // Private Functions 24 | // ---------------------------------------------------------------------------- 25 | static size_t write_callback(void *contents, size_t size, size_t nmemb, 26 | void *ctx) 27 | { 28 | size_t bytes = size * nmemb; 29 | struct WebPage *webpage = ctx; 30 | 31 | webpage->buffer = xrealloc(webpage->buffer, webpage->size + bytes + 1); 32 | memcpy(webpage->buffer + webpage->size, contents, bytes); 33 | webpage->size += bytes; 34 | webpage->buffer[webpage->size] = '\0'; 35 | 36 | return bytes; 37 | } 38 | 39 | static char *encode_payload(char *key, char *value) 40 | { 41 | char *encoded_payload; 42 | char *encoded_value = curl_easy_escape(NULL, value, 0); 43 | 44 | if (encoded_value == NULL) { 45 | die("libcurl: Cannot encode payload"); 46 | } 47 | 48 | uint16_t length = strlen(key) + strlen(encoded_value) + 2; 49 | encoded_payload = malloc(length); 50 | 51 | snprintf(encoded_payload, length, "%s=%s", key, encoded_value); 52 | 53 | curl_free(encoded_value); 54 | return encoded_payload; 55 | } 56 | 57 | // ---------------------------------------------------------------------------- 58 | // Main Functions 59 | // ---------------------------------------------------------------------------- 60 | void web_client_init() 61 | { 62 | self = xmalloc(sizeof(struct WebClient)); 63 | 64 | curl_global_init(CURL_GLOBAL_ALL); 65 | self->handle = curl_easy_init(); 66 | 67 | /* webpage */ 68 | self->webpage.size = 0; 69 | self->webpage.buffer = xmalloc(1); 70 | curl_easy_setopt(self->handle, CURLOPT_WRITEFUNCTION, write_callback); 71 | curl_easy_setopt(self->handle, CURLOPT_WRITEDATA, &self->webpage); 72 | } 73 | 74 | void web_client_cleanup() 75 | { 76 | /* Cleanup CURL stuff */ 77 | curl_easy_cleanup(self->handle); 78 | 79 | free(self->webpage.buffer); 80 | 81 | /* We're done with libcurl, so clean it up */ 82 | curl_global_cleanup(); 83 | 84 | free(self); 85 | } 86 | 87 | void web_client_seturl(char *url, char *referer) 88 | { 89 | unsigned int length = URL_BUF_SIZE - 1; 90 | 91 | strncpy(self->url, url, length); 92 | self->url[length] = '\0'; 93 | 94 | curl_easy_setopt(self->handle, CURLOPT_URL, self->url); 95 | curl_easy_setopt(self->handle, CURLOPT_REFERER, referer); 96 | } 97 | 98 | void web_client_setpayload(char *key, char *value) 99 | { 100 | char sep = '?'; 101 | char *encoded_payload = encode_payload(key, value); 102 | unsigned int length = strnlen(self->url, URL_BUF_SIZE); 103 | 104 | if (strchr(self->url, '?') != NULL) 105 | sep = '&'; 106 | 107 | // concatenate string using formatted strings 108 | snprintf(self->url + length, URL_BUF_SIZE - length, "%c%s", sep, 109 | encoded_payload); 110 | 111 | curl_easy_setopt(self->handle, CURLOPT_URL, self->url); 112 | 113 | free(encoded_payload); 114 | } 115 | 116 | char *web_client_perform() 117 | { 118 | self->webpage.size = 0; 119 | CURLcode err = curl_easy_perform(self->handle); 120 | if (err != CURLE_OK) { 121 | die("libcurl: (%d) %s", err, curl_easy_strerror(err)); 122 | } 123 | 124 | return self->webpage.buffer; 125 | } 126 | -------------------------------------------------------------------------------- /src/web_client.h: -------------------------------------------------------------------------------- 1 | #ifndef CANIME_WEB_CLIENT_H 2 | #define CANIME_WEB_CLIENT_H 3 | 4 | #define URL_BUF_SIZE 256 5 | 6 | // Initialize WebClient 7 | void web_client_init(); 8 | 9 | // Cleanup web_client 10 | void web_client_cleanup(); 11 | 12 | // Set the URL 13 | void web_client_seturl(char *url, char *referer); 14 | 15 | // Set the payload 16 | void web_client_setpayload(char *key, char *value); 17 | 18 | // Perform the transfer 19 | char *web_client_perform(); 20 | 21 | #endif /* CANIME_WEB_CLIENT_H */ 22 | --------------------------------------------------------------------------------