libyml-0.0.5/Cargo.lock0000644000000023110000000000100102760ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anyhow" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "libyml" version = "0.0.5" dependencies = [ "anyhow", "pretty_assertions", "version_check", ] [[package]] name = "pretty_assertions" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", "yansi", ] [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" libyml-0.0.5/Cargo.toml0000644000000114250000000000100103270ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56.0" name = "libyml" version = "0.0.5" authors = ["LibYML Contributors"] build = false exclude = [ "/.git/*", "/.github/*", "/.gitignore", "/.vscode/*", ] include = [ "/CONTRIBUTING.md", "/LICENSE-MIT", "/benches/**", "/build.rs", "/Cargo.toml", "/examples/**", "/README.md", "/src/**", "/tests/**", ] autobins = false autoexamples = false autotests = false autobenches = false description = "A safe and efficient Rust library for parsing, emitting, and manipulating YAML data." homepage = "https://libyml.com" documentation = "https://docs.rs/libyml" readme = "README.md" keywords = [ "yaml", "serde", "serialization", ] categories = [ "encoding", "parser-implementations", "no-std", ] license = "MIT" repository = "https://github.com/sebastienrousseau/libyml" [package.metadata.clippy] warn-lints = [ "clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery", ] [package.metadata.docs.rs] rustdoc-args = ["--generate-link-to-definition"] targets = ["x86_64-unknown-linux-gnu"] [profile.dev] opt-level = 0 lto = false codegen-units = 256 debug = 2 debug-assertions = true rpath = false panic = "unwind" overflow-checks = true incremental = true strip = false [profile.release] opt-level = "s" lto = true codegen-units = 1 debug = 0 debug-assertions = false rpath = false panic = "abort" overflow-checks = false incremental = false strip = "symbols" [profile.test] opt-level = 0 lto = false codegen-units = 256 debug = 2 debug-assertions = true rpath = false overflow-checks = true incremental = true strip = false [lib] name = "libyml" crate-type = ["lib"] path = "src/lib.rs" doc-scrape-examples = false [[bin]] name = "run-emitter-test-suite" path = "src/bin/run-emitter-test-suite.rs" [[bin]] name = "run-parser-test-suite" path = "src/bin/run-parser-test-suite.rs" [[example]] name = "apis" path = "examples/apis/main.rs" [[example]] name = "example" path = "examples/example.rs" [[test]] name = "test_api" path = "tests/test_api.rs" [[test]] name = "test_decode" path = "tests/test_decode.rs" [[test]] name = "test_document" path = "tests/test_document.rs" [[test]] name = "test_dumper" path = "tests/test_dumper.rs" [[test]] name = "test_emitter" path = "tests/test_emitter.rs" [[test]] name = "test_internal" path = "tests/test_internal.rs" [[test]] name = "test_lib" path = "tests/test_lib.rs" [[test]] name = "test_loader" path = "tests/test_loader.rs" [[test]] name = "test_macros" path = "tests/test_macros.rs" [[test]] name = "test_memory" path = "tests/test_memory.rs" [[test]] name = "test_parser" path = "tests/test_parser.rs" [[test]] name = "test_parser_error" path = "tests/test_parser_error.rs" [[test]] name = "test_string" path = "tests/test_string.rs" [[test]] name = "test_yaml" path = "tests/test_yaml.rs" [dependencies.anyhow] version = "1.0.86" [dev-dependencies.pretty_assertions] version = "1.4.0" [build-dependencies.version_check] version = "0.9.5" [features] default = [] test-utils = [] [lints.rust] bare_trait_objects = "allow" box_pointers = "warn" dead_code = "deny" deprecated_in_future = "deny" elided_lifetimes_in_paths = "allow" ellipsis_inclusive_range_patterns = "deny" explicit_outlives_requirements = "deny" macro_use_extern_crate = "deny" meta_variable_misuse = "deny" missing_copy_implementations = "warn" missing_debug_implementations = "forbid" missing_docs = "warn" missing_fragment_specifier = "deny" non_ascii_idents = "forbid" non_camel_case_types = "allow" non_upper_case_globals = "allow" noop_method_call = "deny" single_use_lifetimes = "deny" trivial_bounds = "allow" trivial_casts = "deny" trivial_numeric_casts = "deny" unreachable_pub = "forbid" unsafe_code = "allow" unstable_features = "warn" unused_crate_dependencies = "allow" unused_extern_crates = "warn" unused_features = "deny" unused_import_braces = "deny" unused_labels = "deny" unused_lifetimes = "deny" unused_macro_rules = "deny" unused_qualifications = "deny" unused_results = "warn" variant_size_differences = "deny" [lints.rust.future_incompatible] level = "deny" priority = -1 [lints.rust.keyword_idents] level = "deny" priority = -1 [lints.rust.rust_2018_idioms] level = "deny" priority = -1 [lints.rust.rust_2021_compatibility] level = "deny" priority = -1 [lints.rust.unused] level = "deny" priority = -1 libyml-0.0.5/Cargo.toml.orig000064400000000000000000000122321046102023000140050ustar 00000000000000[package] # Metadata about the package authors = ["LibYML Contributors"] categories = ["encoding", "parser-implementations", "no-std"] description = "A safe and efficient Rust library for parsing, emitting, and manipulating YAML data." documentation = "https://docs.rs/libyml" edition = "2021" exclude = ["/.git/*", "/.github/*", "/.gitignore", "/.vscode/*"] homepage = "https://libyml.com" keywords = ["yaml", "serde", "serialization"] license = "MIT" name = "libyml" readme = "README.md" repository = "https://github.com/sebastienrousseau/libyml" rust-version = "1.56.0" version = "0.0.5" # Specify which files to include in the package include = [ "/CONTRIBUTING.md", "/LICENSE-MIT", "/benches/**", "/build.rs", "/Cargo.toml", "/examples/**", "/README.md", "/src/**", "/tests/**", ] [dependencies] # General dependencies for the package anyhow = "1.0.86" # Rust library for reporting multiple error types through a single type. [build-dependencies] # Dependencies specifically for build scripts version_check = "0.9.5" # Check the Rust version used to compile the package. [dev-dependencies] # Dependencies used during development and testing pretty_assertions = "1.4.0" # Pretty assertions for tests. libyml-test-suite = { path = "tests/data" } # Local dependency for test suite. [features] # Define optional features for the package default = [] # No default features test-utils = [] # Feature for test utilities [lib] # Library configuration options crate-type = ["lib"] name = "libyml" path = "src/lib.rs" doc-scrape-examples = false # Disable scraping of examples for documentation [package.metadata.docs.rs] # Metadata for generating documentation on docs.rs targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--generate-link-to-definition"] # Linting configuration [lints.rust] ## Warn box_pointers = "warn" # Warn on usage of heap-allocated pointers missing_copy_implementations = "warn" # Warn if a `Copy` implementation is missing missing_docs = "warn" # Warn if documentation is missing unstable_features = "warn" # Warn on unstable features unused_extern_crates = "warn" # Warn on unused external crates unused_results = "warn" # Warn if the result of a function is unused ## Allow bare_trait_objects = "allow" # Allow usage of bare trait objects elided_lifetimes_in_paths = "allow" # Allow omitted lifetimes in paths non_camel_case_types = "allow" # Allow types not in camel case non_upper_case_globals = "allow" # Allow global variables not in upper case trivial_bounds = "allow" # Allow trivial bounds in trait declarations unused_crate_dependencies = "allow" # Allow unused crate dependencies unsafe_code = "allow" # Allow usage of unsafe code ## Forbid missing_debug_implementations = "forbid" # Forbid missing Debug implementations non_ascii_idents = "forbid" # Forbid non-ASCII identifiers unreachable_pub = "forbid" # Forbid unreachable public items ## Deny dead_code = "deny" # Deny dead code deprecated_in_future = "deny" # Deny features deprecated in future Rust versions ellipsis_inclusive_range_patterns = "deny" # Deny ellipsis in inclusive range patterns explicit_outlives_requirements = "deny" # Deny unnecessary lifetime bounds future_incompatible = { level = "deny", priority = -1 } # Deny future-incompatible changes keyword_idents = { level = "deny", priority = -1 } # Deny keywords used as identifiers macro_use_extern_crate = "deny" # Deny `extern crate` with `macro_use` meta_variable_misuse = "deny" # Deny misuse of macro variables missing_fragment_specifier = "deny" # Deny missing fragment specifiers in macros noop_method_call = "deny" # Deny no-op method calls rust_2018_idioms = { level = "deny", priority = -1 } # Deny idioms from the 2018 edition rust_2021_compatibility = { level = "deny", priority = -1 } # Deny issues with Rust 2021 edition single_use_lifetimes = "deny" # Deny single-use lifetimes trivial_casts = "deny" # Deny trivial casts trivial_numeric_casts = "deny" # Deny trivial numeric casts unused = { level = "deny", priority = -1 } # Deny unused code unused_features = "deny" # Deny unused features unused_import_braces = "deny" # Deny unused import braces unused_labels = "deny" # Deny unused labels unused_lifetimes = "deny" # Deny unused lifetimes unused_macro_rules = "deny" # Deny unused macro rules unused_qualifications = "deny" # Deny unused qualifications variant_size_differences = "deny" # Deny variant size differences [package.metadata.clippy] # Clippy linting configuration warn-lints = [ "clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery", ] [profile.dev] # Profile settings for development builds codegen-units = 256 debug = true debug-assertions = true incremental = true lto = false opt-level = 0 overflow-checks = true panic = 'unwind' rpath = false strip = false [profile.release] # Profile settings for release builds codegen-units = 1 debug = false debug-assertions = false incremental = false lto = true opt-level = "s" overflow-checks = false panic = "abort" rpath = false strip = "symbols" [profile.test] # Profile settings for test builds codegen-units = 256 debug = true debug-assertions = true incremental = true lto = false opt-level = 0 overflow-checks = true rpath = false strip = false libyml-0.0.5/LICENSE-MIT000064400000000000000000000017771046102023000125660ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libyml-0.0.5/README.md000064400000000000000000000114521046102023000124000ustar 00000000000000 LibYML logo # LibYML (a fork of unsafe-libyaml) [![Made With Love][made-with-rust]][10] [![Crates.io][crates-badge]][06] [![lib.rs][libs-badge]][11] [![Docs.rs][docs-badge]][07] [![Codecov][codecov-badge]][08] [![Build Status][build-badge]][09] [![GitHub][github-badge]][05] LibYML is a Rust library for working with YAML data, forked from [unsafe-libyaml][01]. It offers a safe and efficient interface for parsing, emitting, and manipulating YAML data. ## Features - **Serialization and Deserialization**: Easy-to-use APIs for serializing Rust structs and enums to YAML and vice versa. - **Custom Struct and Enum Support**: Seamless serialization and deserialization of custom data types. - **Comprehensive Error Handling**: Detailed error messages and recovery mechanisms. - **Streaming Support**: Efficient processing of large YAML documents. - **Alias and Anchor Support**: Handling of complex YAML structures with references. - **Tag Handling**: Support for custom tags and type-specific serialization. - **Configurable Emitter**: Customizable YAML output generation. - **Extensive Documentation**: Detailed docs and examples for easy onboarding. - **Safety and Efficiency**: Minimized unsafe code with an interface designed to prevent common pitfalls. ## Installation Add this to your `Cargo.toml`: ```toml [dependencies] libyml = "0.0.5" ``` ## Usage Here's a quick example on how to use LibYML to parse a YAML string: ```rust use core::mem::MaybeUninit; use libyml::{ success::is_success, yaml_parser_delete, yaml_parser_initialize, yaml_parser_parse, yaml_parser_set_input_string, YamlEventT, YamlParserT, }; fn main() { unsafe { let mut parser = MaybeUninit::::uninit(); if is_success(yaml_parser_initialize(parser.as_mut_ptr())) { let mut parser = parser.assume_init(); let yaml = "{key1: value1, key2: [item1, item2]}"; yaml_parser_set_input_string( &mut parser, yaml.as_ptr(), yaml.len() as u64, ); let mut event = MaybeUninit::::uninit(); let result = yaml_parser_parse(&mut parser, event.as_mut_ptr()); if is_success(result) { // Process the event here } else { // Failed to parse YAML } yaml_parser_delete(&mut parser); } else { // Failed to initialize parser } } } ``` ## Documentation For full API documentation, please visit [https://doc.libyml.com/libyml/][03] or [https://docs.rs/libyml][07]. ## Rust Version Compatibility Compiler support: requires rustc 1.56.0+ ## Contributing Contributions are welcome! If you'd like to contribute, please feel free to submit a Pull Request on [GitHub][05]. ## Credits and Acknowledgements LibYML is a fork of the work done by [David Tolnay][04] and the maintainers of [unsafe-libyaml][01]. While it has evolved into a separate library, we express our sincere gratitude to them as well as the [libyaml][02] maintainers for their contributions to the Rust and C programming communities. ## License [MIT license](LICENSE-MIT), same as libyaml. [00]: https://libyml.com [01]: https://github.com/dtolnay/unsafe-libyaml [02]: https://github.com/yaml/libyaml/tree/2c891fc7a770e8ba2fec34fc6b545c672beb37e6 [03]: https://doc.libyml.com/libyml/ [04]: https://github.com/dtolnay [05]: https://github.com/sebastienrousseau/libyml [06]: https://crates.io/crates/libyml [07]: https://docs.rs/libyml [08]: https://codecov.io/gh/sebastienrousseau/libyml [09]: https://github.com/sebastienrousseau/libyml/actions?query=branch%3Amaster [10]: https://www.rust-lang.org/ [11]: https://lib.rs/crates/libyml [build-badge]: https://img.shields.io/github/actions/workflow/status/sebastienrousseau/libyml/release.yml?branch=master&style=for-the-badge&logo=github "Build Status" [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/libyml?style=for-the-badge&logo=codecov&token=yc9s578xIk "Code Coverage" [crates-badge]: https://img.shields.io/crates/v/libyml.svg?style=for-the-badge&color=fc8d62&logo=rust "View on Crates.io" [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.5-orange.svg?style=for-the-badge "View on lib.rs" [docs-badge]: https://img.shields.io/badge/docs.rs-libyml-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs "View Documentation" [github-badge]: https://img.shields.io/badge/github-sebastienrousseau/libyml-8da0cb?style=for-the-badge&labelColor=555555&logo=github "View on GitHub" [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' libyml-0.0.5/examples/apis/main.rs000064400000000000000000000063761046102023000151760ustar 00000000000000#![allow(missing_docs)] use core::mem::MaybeUninit; pub(crate) use core::primitive::u8 as yaml_char_t; use core::ptr; use libyml::api::yaml_parser_set_input_string; use libyml::decode::{yaml_parser_delete, yaml_parser_initialize}; use libyml::memory::{ yaml_free, yaml_malloc, yaml_realloc, yaml_strdup, }; use libyml::string::{yaml_string_extend, yaml_string_join}; pub(crate) fn main() { // Print a message to indicate the file being executed. println!("\n❯ Executing examples/apis/yaml_parser_delete.rs"); let mut parser = MaybeUninit::uninit(); let parser_ptr = parser.as_mut_ptr(); unsafe { let _ = yaml_parser_initialize(parser_ptr); println!( "✅ Successfully initialized the YAML parser:\n{:#?}", parser.assume_init() ); let input = b"key: value\n"; yaml_parser_set_input_string( parser_ptr, input.as_ptr(), input.len().try_into().unwrap(), ); println!( "✅ Successfully set the input string for the YAML parser" ); // Example: yaml_malloc let size = 1024; let ptr = yaml_malloc(size); // Use the allocated memory yaml_free(ptr); println!("✅ Successfully allocated and freed memory"); // Example: yaml_realloc let size = 1024; let ptr = yaml_malloc(size); // Reallocate the memory let new_size = 2048; let new_ptr = yaml_realloc(ptr, new_size); // Use the reallocated memory yaml_free(new_ptr); println!("✅ Successfully reallocated and freed memory"); // Example: yaml_strdup let str = b"Hello, world!\0" as *const yaml_char_t; let dup_str = yaml_strdup(str); // Use the duplicated string yaml_free(dup_str as *mut std::ffi::c_void); println!("✅ Successfully duplicated and freed the string"); // Example: yaml_string_extend let mut start = ptr::null_mut::(); let mut pointer = ptr::null_mut::(); let mut end = ptr::null_mut::(); yaml_string_extend(&mut start, &mut pointer, &mut end); // Use the extended string buffer yaml_free(start as *mut std::ffi::c_void); println!( "✅ Successfully extended and freed the string buffer" ); // Example: yaml_string_join let mut a_start = ptr::null_mut::(); let mut a_pointer = ptr::null_mut::(); let mut a_end = ptr::null_mut::(); let mut b_start = ptr::null_mut::(); let mut b_pointer = ptr::null_mut::(); let mut b_end = ptr::null_mut::(); yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); println!("✅ Successfully joined the string buffers"); // Use the joined string buffer yaml_free(a_start as *mut std::ffi::c_void); println!("✅ Successfully freed the joined string buffer"); yaml_parser_delete(parser_ptr); println!("✅ Successfully deleted the YAML parser"); } } libyml-0.0.5/examples/apis/mod.rs000064400000000000000000000001101046102023000150050ustar 00000000000000/// This module contains the apis `main` examples. pub(crate) mod main; libyml-0.0.5/examples/example.rs000064400000000000000000000005751046102023000147440ustar 00000000000000#![allow(missing_docs)] /// This module contains the `yaml_parser_initialize` example. mod apis; /// The main function that runs all the example modules. /// /// This function is responsible for running all the example modules. /// It does this by calling the `main` function of each example module. /// fn main() { // Run the example module `apis`. apis::main::main(); } libyml-0.0.5/src/api.rs000064400000000000000000001075221046102023000130330ustar 00000000000000use crate::{ externs::{memcpy, memset, strlen}, internal::yaml_check_utf8, libc, memory::{yaml_free, yaml_malloc, yaml_strdup}, ops::ForceAdd as _, success::{Success, FAIL, OK}, yaml::{size_t, yaml_char_t}, PointerExt, YamlAliasEvent, YamlAliasToken, YamlAnchorToken, YamlAnyEncoding, YamlBreakT, YamlEmitterStateT, YamlEmitterT, YamlEncodingT, YamlEventT, YamlEventTypeT::{ YamlDocumentStartEvent, YamlScalarEvent, YamlStreamEndEvent, }, YamlMappingEndEvent, YamlMappingStartEvent, YamlMappingStyleT, YamlMarkT, YamlParserT, YamlReadHandlerT, YamlScalarStyleT, YamlScalarToken, YamlSequenceEndEvent, YamlSequenceStartEvent, YamlSequenceStyleT, YamlStreamStartEvent, YamlTagDirectiveT, YamlTagDirectiveToken, YamlTagToken, YamlTokenT, YamlWriteHandlerT, }; use core::{ mem::size_of, ptr::{self, addr_of_mut}, }; const OUTPUT_BUFFER_SIZE: usize = 16384; const OUTPUT_RAW_BUFFER_SIZE: usize = OUTPUT_BUFFER_SIZE * 2 + 2; unsafe fn yaml_string_read_handler( data: *mut libc::c_void, buffer: *mut libc::c_uchar, mut size: size_t, size_read: *mut size_t, ) -> libc::c_int { let parser: *mut YamlParserT = data as *mut YamlParserT; if (*parser).input.string.current == (*parser).input.string.end { *size_read = 0_u64; return 1; } if size > (*parser) .input .string .end .c_offset_from((*parser).input.string.current) as size_t { size = (*parser) .input .string .end .c_offset_from((*parser).input.string.current) as size_t; } let _ = memcpy( buffer as *mut libc::c_void, (*parser).input.string.current as *const libc::c_void, size, ); let fresh80 = addr_of_mut!((*parser).input.string.current); *fresh80 = (*fresh80).wrapping_offset(size as isize); *size_read = size; 1 } /// Set a string input. /// /// This function sets the input source for the parser to a string buffer. /// Note that the `input` pointer must be valid while the `parser` object /// exists. The application is responsible for destroying `input` after /// destroying the `parser`. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - The `YamlParserT` struct must not have an input handler already set. /// - `input` must be a valid, non-null pointer to a null-terminated string buffer. /// - The `input` string buffer must remain valid and unmodified until the `parser` object is destroyed. /// - The `YamlParserT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_parser_set_input_string( parser: *mut YamlParserT, input: *const libc::c_uchar, size: size_t, ) { assert!(!parser.is_null()); assert!((*parser).read_handler.is_none()); assert!(!input.is_null()); (*parser).read_handler = Some(yaml_string_read_handler); (*parser).read_handler_data = parser as *mut libc::c_void; (*parser).input.string.start = input; (*parser).input.string.current = input; (*parser).input.string.end = input.wrapping_offset(size as isize); } /// Set a generic input handler. /// /// This function sets a custom input handler for the parser. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - The `YamlParserT` struct must not have an input handler already set. /// - `handler` must be a valid function pointer that follows the signature of `YamlReadHandlerT`. /// - `data` must be a valid pointer that will be passed to the `handler` function. /// - The `YamlParserT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_parser_set_input( parser: *mut YamlParserT, handler: YamlReadHandlerT, data: *mut libc::c_void, ) { __assert!(!parser.is_null()); __assert!(((*parser).read_handler).is_none()); let fresh89 = addr_of_mut!((*parser).read_handler); *fresh89 = Some(handler); let fresh90 = addr_of_mut!((*parser).read_handler_data); *fresh90 = data; } /// Set the source encoding. /// /// This function sets the expected encoding of the input source for the parser. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - The `YamlParserT` struct must not have an encoding already set, or the encoding must be `YamlAnyEncoding`. /// - The `YamlParserT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_parser_set_encoding( parser: *mut YamlParserT, encoding: YamlEncodingT, ) { __assert!(!parser.is_null()); __assert!((*parser).encoding == YamlAnyEncoding); (*parser).encoding = encoding; } /// Initialize an emitter. /// /// This function creates a new emitter object. An application is responsible /// for destroying the object using the yaml_emitter_delete() function. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to an uninitialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for properly destroying the emitter object using `yaml_emitter_delete`. /// pub unsafe fn yaml_emitter_initialize( emitter: *mut YamlEmitterT, ) -> Success { __assert!(!emitter.is_null()); let _ = memset( emitter as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); BUFFER_INIT!((*emitter).buffer, OUTPUT_BUFFER_SIZE); BUFFER_INIT!((*emitter).raw_buffer, OUTPUT_RAW_BUFFER_SIZE); STACK_INIT!((*emitter).states, YamlEmitterStateT); QUEUE_INIT!((*emitter).events, YamlEventT); STACK_INIT!((*emitter).indents, libc::c_int); STACK_INIT!((*emitter).tag_directives, YamlTagDirectiveT); OK } /// Destroy an emitter. /// /// This function frees all memory associated with an emitter object, including /// any dynamically allocated buffers, events, and other data structures. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must have been properly initialized and their memory allocated correctly. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// - After calling this function, the `emitter` pointer should be considered invalid and should not be used again. /// pub unsafe fn yaml_emitter_delete(emitter: *mut YamlEmitterT) { __assert!(!emitter.is_null()); BUFFER_DEL!((*emitter).buffer); BUFFER_DEL!((*emitter).raw_buffer); STACK_DEL!((*emitter).states); while !QUEUE_EMPTY!((*emitter).events) { yaml_event_delete(addr_of_mut!(DEQUEUE!((*emitter).events))); } QUEUE_DEL!((*emitter).events); STACK_DEL!((*emitter).indents); while !STACK_EMPTY!((*emitter).tag_directives) { let tag_directive = POP!((*emitter).tag_directives); yaml_free(tag_directive.handle as *mut libc::c_void); yaml_free(tag_directive.prefix as *mut libc::c_void); } STACK_DEL!((*emitter).tag_directives); yaml_free((*emitter).anchors as *mut libc::c_void); let _ = memset( emitter as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); } unsafe fn yaml_string_write_handler( data: *mut libc::c_void, buffer: *mut libc::c_uchar, size: size_t, ) -> libc::c_int { let emitter: *mut YamlEmitterT = data as *mut YamlEmitterT; if (*emitter) .output .string .size .wrapping_sub(*(*emitter).output.string.size_written) < size { let _ = memcpy( (*emitter).output.string.buffer.wrapping_offset( *(*emitter).output.string.size_written as isize, ) as *mut libc::c_void, buffer as *const libc::c_void, (*emitter).output.string.size.wrapping_sub( *(*emitter).output.string.size_written, ), ); *(*emitter).output.string.size_written = (*emitter).output.string.size; return 0; } let _ = memcpy( (*emitter).output.string.buffer.wrapping_offset( *(*emitter).output.string.size_written as isize, ) as *mut libc::c_void, buffer as *const libc::c_void, size, ); let fresh153 = addr_of_mut!((*(*emitter).output.string.size_written)); *fresh153 = (*fresh153).wrapping_add(size); 1 } /// Set a string output. /// /// This function sets the output destination for the emitter to a string buffer. /// The emitter will write the output characters to the `output` buffer of the /// specified `size`. The emitter will set `size_written` to the number of written /// bytes. If the buffer is smaller than required, the emitter produces the /// YAML_write_ERROR error. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must not have an output handler already set. /// - `output` must be a valid, non-null pointer to a writeable buffer of size `size`. /// - `size_written` must be a valid, non-null pointer to a `size_t` variable. /// - The `output` buffer must remain valid and unmodified until the emitter is destroyed or the output is reset. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_output_string( emitter: *mut YamlEmitterT, output: *mut libc::c_uchar, size: size_t, size_written: *mut size_t, ) { assert!(!emitter.is_null()); assert!((*emitter).write_handler.is_none()); assert!(!output.is_null()); (*emitter).write_handler = Some(yaml_string_write_handler); (*emitter).write_handler_data = emitter as *mut libc::c_void; (*emitter).output.string.buffer = output; (*emitter).output.string.size = size; *size_written = 0; } /// Set a generic output handler. /// /// This function sets a custom output handler for the emitter. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must not have an output handler already set. /// - `handler` must be a valid function pointer that follows the signature of `YamlWriteHandlerT`. /// - `data` must be a valid pointer that will be passed to the `handler` function. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_output( emitter: *mut YamlEmitterT, handler: YamlWriteHandlerT, data: *mut libc::c_void, ) { __assert!(!emitter.is_null()); __assert!(((*emitter).write_handler).is_none()); let fresh161 = addr_of_mut!((*emitter).write_handler); *fresh161 = Some(handler); let fresh162 = addr_of_mut!((*emitter).write_handler_data); *fresh162 = data; } /// Set the output encoding. /// /// This function sets the encoding to be used for the output by the emitter. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must not have an encoding already set, or the encoding must be `YamlAnyEncoding`. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_encoding( emitter: *mut YamlEmitterT, encoding: YamlEncodingT, ) { __assert!(!emitter.is_null()); __assert!((*emitter).encoding == YamlAnyEncoding); (*emitter).encoding = encoding; } /// Set if the output should be in the "canonical" format as in the YAML /// specification. /// /// This function sets whether the emitter should produce output in the canonical /// format, as defined by the YAML specification. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_canonical( emitter: *mut YamlEmitterT, canonical: bool, ) { __assert!(!emitter.is_null()); (*emitter).canonical = canonical; } /// Set the indentation increment. /// /// This function sets the indentation increment to be used by the emitter when /// emitting indented content. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_indent( emitter: *mut YamlEmitterT, indent: libc::c_int, ) { __assert!(!emitter.is_null()); (*emitter).best_indent = if 1 < indent && indent < 10 { indent } else { 2 }; } /// Set the preferred line width. -1 means unlimited. /// /// This function sets the preferred line width for the emitter's output. /// A value of -1 means that the line width is unlimited. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_width( emitter: *mut YamlEmitterT, width: libc::c_int, ) { __assert!(!emitter.is_null()); (*emitter).best_width = if width >= 0 { width } else { -1 }; } /// Set if unescaped non-ASCII characters are allowed. /// /// This function sets whether the emitter should allow unescaped non-ASCII /// characters in its output. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_unicode( emitter: *mut YamlEmitterT, unicode: bool, ) { __assert!(!emitter.is_null()); (*emitter).unicode = unicode; } /// Set the preferred line break. /// /// This function sets the preferred line break character to be used by the emitter. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_set_break( emitter: *mut YamlEmitterT, line_break: YamlBreakT, ) { __assert!(!emitter.is_null()); (*emitter).line_break = line_break; } /// Free any memory allocated for a token object. /// /// This function frees the dynamically allocated memory associated with a `YamlTokenT` struct, /// such as strings for tag directives, aliases, anchors, tags, and scalar values. /// /// # Safety /// /// - `token` must be a valid, non-null pointer to a `YamlTokenT` struct. /// - The `YamlTokenT` struct must have been properly initialized and its memory allocated correctly. /// - The `YamlTokenT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_token_delete(token: *mut YamlTokenT) { __assert!(!token.is_null()); match (*token).type_ { YamlTagDirectiveToken => { yaml_free( (*token).data.tag_directive.handle as *mut libc::c_void, ); yaml_free( (*token).data.tag_directive.prefix as *mut libc::c_void, ); } YamlAliasToken => { yaml_free((*token).data.alias.value as *mut libc::c_void); } YamlAnchorToken => { yaml_free((*token).data.anchor.value as *mut libc::c_void); } YamlTagToken => { yaml_free((*token).data.tag.handle as *mut libc::c_void); yaml_free((*token).data.tag.suffix as *mut libc::c_void); } YamlScalarToken => { yaml_free((*token).data.scalar.value as *mut libc::c_void); } _ => {} } let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); } /// Create the STREAM-START event. /// /// This function initializes a `YamlEventT` struct with the type `YamlStreamStartEvent`. /// It is used to signal the start of a YAML stream being emitted. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_stream_start_event_initialize( event: *mut YamlEventT, encoding: YamlEncodingT, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlStreamStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.stream_start.encoding = encoding; OK } /// Create the STREAM-END event. /// /// This function initializes a `YamlEventT` struct with the type `YamlStreamEndEvent`. /// It is used to signal the end of a YAML stream being emitted. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_stream_end_event_initialize( event: *mut YamlEventT, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlStreamEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; OK } /// Create an ALIAS event. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `anchor` must be a valid, non-null pointer to a null-terminated UTF-8 string. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// pub unsafe fn yaml_alias_event_initialize( event: *mut YamlEventT, anchor: *const yaml_char_t, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); __assert!(!anchor.is_null()); if yaml_check_utf8(anchor, strlen(anchor as *mut libc::c_char)).fail { return FAIL; } let anchor_copy: *mut yaml_char_t = yaml_strdup(anchor); if anchor_copy.is_null() { return FAIL; } let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlAliasEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh167 = addr_of_mut!((*event).data.alias.anchor); *fresh167 = anchor_copy; OK } /// Create a SCALAR event. /// /// The `style` argument may be ignored by the emitter. /// /// Either the `tag` attribute or one of the `plain_implicit` and /// `quoted_implicit` flags must be set. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `data.value` must be a valid, non-null pointer to a null-terminated UTF-8 string. /// - `data.anchor`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - `data.tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(C)] pub struct ScalarEventData<'a> { /// Anchor name or null. pub anchor: *const yaml_char_t, /// Tag or null. pub tag: *const yaml_char_t, /// Value. pub value: *const yaml_char_t, /// Value length. pub length: libc::c_int, /// Is the tag optional for the plain style? pub plain_implicit: bool, /// Is the tag optional for any non-plain style? pub quoted_implicit: bool, /// Scalar style. pub style: YamlScalarStyleT, /// Lifetime marker. pub _marker: core::marker::PhantomData<&'a ()>, } /// Create a SCALAR event. /// /// The `style` argument may be ignored by the emitter. /// /// Either the `tag` attribute or one of the `plain_implicit` and /// `quoted_implicit` flags must be set. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `value` must be a valid, non-null pointer to a null-terminated UTF-8 string. /// - `anchor`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// pub unsafe fn yaml_scalar_event_initialize( event: *mut YamlEventT, mut data: ScalarEventData<'_>, ) -> Success { let mut current_block: u64; let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut anchor_copy: *mut yaml_char_t = ptr::null_mut::(); let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); let mut value_copy: *mut yaml_char_t = ptr::null_mut::(); __assert!(!event.is_null()); __assert!(!data.value.is_null()); if !data.anchor.is_null() { if yaml_check_utf8( data.anchor, strlen(data.anchor as *mut libc::c_char), ) .fail { current_block = 16285396129609901221; } else { anchor_copy = yaml_strdup(data.anchor); if anchor_copy.is_null() { current_block = 16285396129609901221; } else { current_block = 8515828400728868193; } } } else { current_block = 8515828400728868193; } if current_block == 8515828400728868193 { if !data.tag.is_null() { if yaml_check_utf8( data.tag, strlen(data.tag as *mut libc::c_char), ) .fail { current_block = 16285396129609901221; } else { tag_copy = yaml_strdup(data.tag); if tag_copy.is_null() { current_block = 16285396129609901221; } else { current_block = 12800627514080957624; } } } else { current_block = 12800627514080957624; } if current_block != 16285396129609901221 { if data.length < 0 { data.length = strlen(data.value as *mut libc::c_char) as libc::c_int; } if yaml_check_utf8(data.value, data.length as size_t).ok { value_copy = yaml_malloc(data.length.force_add(1) as size_t) as *mut yaml_char_t; let _ = memcpy( value_copy as *mut libc::c_void, data.value as *const libc::c_void, data.length as libc::c_ulong, ); *value_copy.wrapping_offset(data.length as isize) = b'\0'; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlScalarEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh168 = addr_of_mut!((*event).data.scalar.anchor); *fresh168 = anchor_copy; let fresh169 = addr_of_mut!((*event).data.scalar.tag); *fresh169 = tag_copy; let fresh170 = addr_of_mut!((*event).data.scalar.value); *fresh170 = value_copy; (*event).data.scalar.length = data.length as size_t; (*event).data.scalar.plain_implicit = data.plain_implicit; (*event).data.scalar.quoted_implicit = data.quoted_implicit; (*event).data.scalar.style = data.style; return OK; } } } yaml_free(anchor_copy as *mut libc::c_void); yaml_free(tag_copy as *mut libc::c_void); yaml_free(value_copy as *mut libc::c_void); FAIL } /// Create a SEQUENCE-START event. /// /// The `style` argument may be ignored by the emitter. /// /// Either the `tag` attribute or the `implicit` flag must be set. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `anchor`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// pub unsafe fn yaml_sequence_start_event_initialize( event: *mut YamlEventT, anchor: *const yaml_char_t, tag: *const yaml_char_t, implicit: bool, style: YamlSequenceStyleT, ) -> Success { let mut current_block: u64; let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut anchor_copy: *mut yaml_char_t = ptr::null_mut::(); let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); __assert!(!event.is_null()); if !anchor.is_null() { if yaml_check_utf8(anchor, strlen(anchor as *mut libc::c_char)) .fail { current_block = 8817775685815971442; } else { anchor_copy = yaml_strdup(anchor); if anchor_copy.is_null() { current_block = 8817775685815971442; } else { current_block = 11006700562992250127; } } } else { current_block = 11006700562992250127; } if current_block == 11006700562992250127 { if !tag.is_null() { if yaml_check_utf8(tag, strlen(tag as *mut libc::c_char)) .fail { current_block = 8817775685815971442; } else { tag_copy = yaml_strdup(tag); if tag_copy.is_null() { current_block = 8817775685815971442; } else { current_block = 7651349459974463963; } } } else { current_block = 7651349459974463963; } if current_block != 8817775685815971442 { let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh171 = addr_of_mut!((*event).data.sequence_start.anchor); *fresh171 = anchor_copy; let fresh172 = addr_of_mut!((*event).data.sequence_start.tag); *fresh172 = tag_copy; (*event).data.sequence_start.implicit = implicit; (*event).data.sequence_start.style = style; return OK; } } yaml_free(anchor_copy as *mut libc::c_void); yaml_free(tag_copy as *mut libc::c_void); FAIL } /// Create a SEQUENCE-END event. /// /// This function initializes a `YamlEventT` struct with the type `YamlSequenceEndEvent`. /// It is used to signal the end of a sequence in the YAML document being emitted. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_sequence_end_event_initialize( event: *mut YamlEventT, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; OK } /// Create a MAPPING-START event. /// /// This function initializes a `YamlEventT` struct with the type `YamlMappingStartEvent`. /// It is used to signal the start of a mapping (key-value pairs) in the YAML document being emitted. /// /// The `style` argument may be ignored by the emitter. /// /// Either the `tag` attribute or the `implicit` flag must be set. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `anchor`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// pub unsafe fn yaml_mapping_start_event_initialize( event: *mut YamlEventT, anchor: *const yaml_char_t, tag: *const yaml_char_t, implicit: bool, style: YamlMappingStyleT, ) -> Success { let mut current_block: u64; let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut anchor_copy: *mut yaml_char_t = ptr::null_mut::(); let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); __assert!(!event.is_null()); if !anchor.is_null() { if yaml_check_utf8(anchor, strlen(anchor as *mut libc::c_char)) .fail { current_block = 14748279734549812740; } else { anchor_copy = yaml_strdup(anchor); if anchor_copy.is_null() { current_block = 14748279734549812740; } else { current_block = 11006700562992250127; } } } else { current_block = 11006700562992250127; } if current_block == 11006700562992250127 { if !tag.is_null() { if yaml_check_utf8(tag, strlen(tag as *mut libc::c_char)) .fail { current_block = 14748279734549812740; } else { tag_copy = yaml_strdup(tag); if tag_copy.is_null() { current_block = 14748279734549812740; } else { current_block = 7651349459974463963; } } } else { current_block = 7651349459974463963; } if current_block != 14748279734549812740 { let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh173 = addr_of_mut!((*event).data.mapping_start.anchor); *fresh173 = anchor_copy; let fresh174 = addr_of_mut!((*event).data.mapping_start.tag); *fresh174 = tag_copy; (*event).data.mapping_start.implicit = implicit; (*event).data.mapping_start.style = style; return OK; } } yaml_free(anchor_copy as *mut libc::c_void); yaml_free(tag_copy as *mut libc::c_void); FAIL } /// Create a MAPPING-END event. /// /// This function initializes a `YamlEventT` struct with the type `YamlMappingEndEvent`. /// It is used to signal the end of a mapping (key-value pairs) in the YAML document being emitted. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_mapping_end_event_initialize( event: *mut YamlEventT, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; OK } /// Free any memory allocated for an event object. /// /// This function frees the dynamically allocated memory associated with a `YamlEventT` struct, /// such as strings for anchors, tags, and scalar values. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct. /// - The `YamlEventT` struct must have been properly initialized and its memory allocated correctly. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_event_delete(event: *mut YamlEventT) { let mut tag_directive: *mut YamlTagDirectiveT; __assert!(!event.is_null()); match (*event).type_ { YamlDocumentStartEvent => { yaml_free( (*event).data.document_start.version_directive as *mut libc::c_void, ); tag_directive = (*event).data.document_start.tag_directives.start; while tag_directive != (*event).data.document_start.tag_directives.end { yaml_free((*tag_directive).handle as *mut libc::c_void); yaml_free((*tag_directive).prefix as *mut libc::c_void); tag_directive = tag_directive.wrapping_offset(1); } yaml_free( (*event).data.document_start.tag_directives.start as *mut libc::c_void, ); } YamlAliasEvent => { yaml_free((*event).data.alias.anchor as *mut libc::c_void); } YamlScalarEvent => { yaml_free((*event).data.scalar.anchor as *mut libc::c_void); yaml_free((*event).data.scalar.tag as *mut libc::c_void); yaml_free((*event).data.scalar.value as *mut libc::c_void); } YamlSequenceStartEvent => { yaml_free( (*event).data.sequence_start.anchor as *mut libc::c_void, ); yaml_free( (*event).data.sequence_start.tag as *mut libc::c_void, ); } YamlMappingStartEvent => { yaml_free( (*event).data.mapping_start.anchor as *mut libc::c_void, ); yaml_free( (*event).data.mapping_start.tag as *mut libc::c_void, ); } _ => {} } let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); } libyml-0.0.5/src/bin/cstr/mod.rs000064400000000000000000000026511046102023000145610ustar 00000000000000use std::fmt::{self, Display, Write as _}; use std::slice; use std::str; #[allow(non_camel_case_types)] type c_char = i8; pub(crate) struct CStr { pub(crate) ptr: *const u8, } impl CStr { pub(crate) unsafe fn from_ptr(ptr: *const c_char) -> Self { CStr { ptr: ptr.cast() } } } impl Display for CStr { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let len = unsafe { strlen(self.ptr) }; let mut bytes = unsafe { slice::from_raw_parts(self.ptr, len) }; loop { match str::from_utf8(bytes) { Ok(valid) => return formatter.write_str(valid), Err(utf8_error) => { let valid_up_to = utf8_error.valid_up_to(); let valid = unsafe { str::from_utf8_unchecked(&bytes[..valid_up_to]) }; formatter.write_str(valid)?; formatter .write_char(char::REPLACEMENT_CHARACTER)?; if let Some(error_len) = utf8_error.error_len() { bytes = &bytes[valid_up_to + error_len..]; } else { return Ok(()); } } } } } } unsafe fn strlen(s: *const u8) -> usize { let mut end = s; while *end != 0 { end = end.add(1); } end.offset_from(s) as usize } libyml-0.0.5/src/bin/run-emitter-test-suite.rs000064400000000000000000000277451046102023000174210ustar 00000000000000#![allow(missing_docs)] #![warn(clippy::pedantic)] #![allow( clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::items_after_statements, clippy::let_underscore_untyped, clippy::missing_errors_doc, clippy::missing_safety_doc, clippy::ptr_as_ptr, clippy::single_match_else, clippy::too_many_lines, clippy::uninlined_format_args, clippy::unreadable_literal )] mod cstr; use self::cstr::CStr; use core::fmt; pub(crate) use core::primitive::u8 as yaml_char_t; use libyml::api::ScalarEventData; use libyml::document::{ yaml_document_end_event_initialize, yaml_document_start_event_initialize, }; use libyml::{ yaml_alias_event_initialize, yaml_emitter_delete, yaml_emitter_emit, yaml_emitter_initialize, yaml_emitter_set_canonical, yaml_emitter_set_output, yaml_emitter_set_unicode, yaml_mapping_end_event_initialize, yaml_mapping_start_event_initialize, yaml_scalar_event_initialize, yaml_sequence_end_event_initialize, yaml_sequence_start_event_initialize, yaml_stream_end_event_initialize, yaml_stream_start_event_initialize, YamlAnyScalarStyle, YamlBlockMappingStyle, YamlBlockSequenceStyle, YamlDoubleQuotedScalarStyle, YamlEmitterError, YamlEmitterT, YamlEventT, YamlFoldedScalarStyle, YamlLiteralScalarStyle, YamlMemoryError, YamlPlainScalarStyle, YamlScalarStyleT, YamlSingleQuotedScalarStyle, YamlTagDirectiveT, YamlUtf8Encoding, YamlVersionDirectiveT, YamlWriterError, }; use std::env; use std::error::Error; use std::ffi::c_void; use std::fs::File; use std::io::{self, Read, Write}; use std::mem::MaybeUninit; use std::process::{self, ExitCode}; use std::ptr::{self, addr_of_mut}; #[derive(Debug)] pub(crate) enum EmitterError { InitializationError(String), MemoryError(String), UnknownEvent(String), EmittingError(String), InternalError, } impl fmt::Display for EmitterError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { EmitterError::InitializationError(msg) | EmitterError::MemoryError(msg) | EmitterError::UnknownEvent(msg) | EmitterError::EmittingError(msg) => { write!(f, "{}", msg) } EmitterError::InternalError => write!(f, "Internal error"), } } } impl Error for EmitterError {} pub(crate) unsafe fn unsafe_main( stdin: &mut dyn Read, mut stdout: &mut dyn Write, ) -> Result<(), EmitterError> { let mut emitter = MaybeUninit::::uninit(); let emitter = emitter.as_mut_ptr(); if yaml_emitter_initialize(emitter).fail { return Err(EmitterError::InitializationError( "Could not initialize the emitter object".into(), )); } unsafe fn write_to_stdio( data: *mut c_void, buffer: *mut u8, size: u64, ) -> i32 { let stdout: *mut &mut dyn Write = data as _; let bytes = std::slice::from_raw_parts(buffer, size as usize); match (*stdout).write(bytes) { Ok(n) => n as i32, Err(_) => 0, } } yaml_emitter_set_output( emitter, write_to_stdio, addr_of_mut!(stdout).cast(), ); yaml_emitter_set_canonical(emitter, false); yaml_emitter_set_unicode(emitter, false); let mut buf = ReadBuf::new(); let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let result = loop { let line = match buf.get_line(stdin) { Some(line) => line, None => break Ok(()), }; let mut anchor = [0u8; 256]; let mut tag = [0u8; 256]; let result = if line.starts_with(b"+STR") { yaml_stream_start_event_initialize(event, YamlUtf8Encoding) } else if line.starts_with(b"-STR") { yaml_stream_end_event_initialize(event) } else if line.starts_with(b"+DOC") { let implicit = !line[4..].starts_with(b" ---"); yaml_document_start_event_initialize( event, ptr::null_mut::(), ptr::null_mut::(), ptr::null_mut::(), implicit, ) } else if line.starts_with(b"-DOC") { let implicit = !line[4..].starts_with(b" ..."); yaml_document_end_event_initialize(event, implicit) } else if line.starts_with(b"+MAP") { yaml_mapping_start_event_initialize( event, get_anchor(b'&', line, anchor.as_mut_ptr()), get_tag(line, tag.as_mut_ptr()), false, YamlBlockMappingStyle, ) } else if line.starts_with(b"-MAP") { yaml_mapping_end_event_initialize(event) } else if line.starts_with(b"+SEQ") { yaml_sequence_start_event_initialize( event, get_anchor(b'&', line, anchor.as_mut_ptr()), get_tag(line, tag.as_mut_ptr()), false, YamlBlockSequenceStyle, ) } else if line.starts_with(b"-SEQ") { yaml_sequence_end_event_initialize(event) } else if line.starts_with(b"=VAL") { let mut value = [0i8; 1024]; let mut style = YamlAnyScalarStyle; get_value(line, value.as_mut_ptr(), &mut style); let implicit = get_tag(line, tag.as_mut_ptr()).is_null(); let scalar_event_data = ScalarEventData { anchor: get_anchor(b'&', line, anchor.as_mut_ptr()), tag: get_tag(line, tag.as_mut_ptr()), value: value.as_mut_ptr() as *const yaml_char_t, length: -1, plain_implicit: implicit, quoted_implicit: implicit, style, _marker: core::marker::PhantomData, }; yaml_scalar_event_initialize(event, scalar_event_data) } else if line.starts_with(b"=ALI") { yaml_alias_event_initialize( event, get_anchor(b'*', line, anchor.as_mut_ptr()), ) } else { let line = line.as_mut_ptr() as *mut i8; break Err(EmitterError::UnknownEvent(format!( "Unknown event: '{}'", CStr::from_ptr(line) ))); }; if result.fail { break Err(EmitterError::MemoryError( "Memory error: Not enough memory for creating an event" .into(), )); } if yaml_emitter_emit(emitter, event).fail { break Err(match (*emitter).error { YamlMemoryError => EmitterError::MemoryError( "Memory error: Not enough memory for emitting" .into(), ), YamlWriterError => { EmitterError::EmittingError(format!( "Writer error: {}", CStr::from_ptr((*emitter).problem) )) } YamlEmitterError => { EmitterError::EmittingError(format!( "Emitter error: {}", CStr::from_ptr((*emitter).problem) )) } _ => EmitterError::InternalError, }); } }; yaml_emitter_delete(emitter); result.map_err(Into::into) } struct ReadBuf { buf: [u8; 1024], offset: usize, filled: usize, } impl ReadBuf { fn new() -> Self { ReadBuf { buf: [0; 1024], offset: 0, filled: 0, } } fn get_line(&mut self, input: &mut dyn Read) -> Option<&mut [u8]> { loop { for i in self.offset..self.offset + self.filled { if self.buf[i] == b'\n' { self.buf[i] = b'\0'; let line = &mut self.buf[self.offset..=i]; self.offset = i + 1; self.filled -= line.len(); return Some(line); } } let mut remainder = &mut self.buf[self.offset + self.filled..]; if remainder.is_empty() { if self.offset == 0 { let _ = writeln!( io::stderr(), "Line too long: '{}'", String::from_utf8_lossy(&self.buf), ); process::abort(); } self.buf.copy_within(self.offset.., 0); self.offset = 0; remainder = &mut self.buf; } let n = input.read(remainder).ok()?; self.filled += n; if n == 0 { return None; } } } } unsafe fn get_anchor( sigil: u8, line: &[u8], anchor: *mut u8, ) -> *mut u8 { let start = match line.iter().position(|ch| *ch == sigil) { Some(offset) => offset + 1, None => return ptr::null_mut(), }; let end = match line[start..].iter().position(|ch| *ch == b' ') { Some(offset) => start + offset, None => line.len(), }; anchor.copy_from_nonoverlapping( line[start..end].as_ptr(), end - start, ); *anchor.add(end - start) = b'\0'; anchor } unsafe fn get_tag(line: &[u8], tag: *mut u8) -> *mut u8 { let start = match line.iter().position(|ch| *ch == b'<') { Some(offset) => offset + 1, None => return ptr::null_mut(), }; let end = match line[start..].iter().position(|ch| *ch == b'>') { Some(offset) => start + offset, None => return ptr::null_mut(), }; tag.copy_from_nonoverlapping( line[start..end].as_ptr(), end - start, ); *tag.add(end - start) = b'\0'; tag } unsafe fn get_value( line: &[u8], value: *mut i8, style: *mut YamlScalarStyleT, ) { let line_len = line.len(); let line = line.as_ptr() as *mut i8; let mut start = ptr::null_mut::(); let end = line.add(line_len); let mut c = line.offset(4); while c < end { if *c as u8 == b' ' { start = c.offset(1); *style = match *start as u8 { b':' => YamlPlainScalarStyle, b'\'' => YamlSingleQuotedScalarStyle, b'"' => YamlDoubleQuotedScalarStyle, b'|' => YamlLiteralScalarStyle, b'>' => YamlFoldedScalarStyle, _ => { start = ptr::null_mut::(); c = c.offset(1); continue; } }; start = start.offset(1); break; } c = c.offset(1); } if start.is_null() { process::abort(); } let mut i = 0; c = start; while c < end { *value.offset(i) = if *c as u8 == b'\\' { c = c.offset(1); match *c as u8 { b'\\' => b'\\' as i8, b'0' => b'\0' as i8, b'b' => b'\x08' as i8, b'n' => b'\n' as i8, b'r' => b'\r' as i8, b't' => b'\t' as i8, _ => process::abort(), } } else { *c }; i += 1; c = c.offset(1); } *value.offset(i) = b'\0' as i8; } fn main() -> ExitCode { let args = env::args_os().skip(1); if args.len() == 0 { let _ = writeln!( io::stderr(), "Usage: run-emitter-test-suite ...", ); return ExitCode::FAILURE; } for arg in args { let mut stdin = File::open(arg).unwrap(); let mut stdout = io::stdout(); let result = unsafe { unsafe_main(&mut stdin, &mut stdout) }; if let Err(err) = result { let _ = writeln!(io::stderr(), "{}", err); return ExitCode::FAILURE; } } ExitCode::SUCCESS } libyml-0.0.5/src/bin/run-parser-test-suite.rs000064400000000000000000000310111046102023000172210ustar 00000000000000//! A YAML parser and formatter using the libyml library. //! //! This program reads YAML files, parses them using the libyml library, //! and outputs a formatted representation of the YAML structure. #![allow(missing_docs)] #![warn(clippy::pedantic)] #![allow( clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::items_after_statements, clippy::let_underscore_untyped, clippy::missing_errors_doc, clippy::missing_safety_doc, clippy::too_many_lines, clippy::uninlined_format_args )] mod cstr; use self::cstr::CStr; use anyhow::{bail, Error, Result}; use libyml::{ yaml_event_delete, yaml_parser_delete, yaml_parser_initialize, yaml_parser_parse, yaml_parser_set_input, YamlAliasEvent, YamlDocumentEndEvent, YamlDocumentStartEvent, YamlDoubleQuotedScalarStyle, YamlEventT, YamlEventTypeT, YamlFoldedScalarStyle, YamlLiteralScalarStyle, YamlMappingEndEvent, YamlMappingStartEvent, YamlNoEvent, YamlParserT, YamlPlainScalarStyle, YamlScalarEvent, YamlSequenceEndEvent, YamlSequenceStartEvent, YamlSingleQuotedScalarStyle, YamlStreamEndEvent, YamlStreamStartEvent, }; use std::env; use std::ffi::c_void; use std::fs::File; use std::io::{self, Read, Write}; use std::mem::MaybeUninit; use std::path::Path; use std::process::ExitCode; use std::ptr::addr_of_mut; use std::slice; /// The main parsing function that processes YAML input and writes formatted output. /// /// # Safety /// /// This function is unsafe because it deals with raw pointers and FFI. /// Callers must ensure that the provided `stdin` and `stdout` are valid /// and that the FFI calls are used correctly. /// /// # Arguments /// /// * `stdin` - A mutable reference to a type that implements `Read`, from which YAML will be read. /// * `stdout` - A mutable reference to a type that implements `Write`, to which formatted output will be written. /// /// # Returns /// /// Returns `Ok(())` if parsing and formatting succeed, or an `Error` if any issues occur. pub(crate) unsafe fn unsafe_main( mut stdin: &mut dyn Read, stdout: &mut dyn Write, ) -> Result<()> { let mut parser = MaybeUninit::::uninit(); let parser = parser.as_mut_ptr(); if yaml_parser_initialize(parser).fail { bail!("Could not initialize the parser object"); } /// Callback function for reading input from stdio. /// /// This function is called by the YAML parser to read input data. /// /// # Safety /// /// This function is unsafe because it deals with raw pointers. /// It assumes that `data` is a valid pointer to a `Read` trait object. unsafe fn read_from_stdio( data: *mut c_void, buffer: *mut u8, size: u64, size_read: *mut u64, ) -> i32 { let stdin: *mut &mut dyn Read = data.cast(); let slice = slice::from_raw_parts_mut(buffer.cast(), size as usize); match (*stdin).read(slice) { Ok(n) => { *size_read = n as u64; 1 } Err(_) => 0, } } yaml_parser_set_input( parser, read_from_stdio, addr_of_mut!(stdin).cast(), ); let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); loop { if yaml_parser_parse(parser, event).fail { let error = format!( "Parse error: {}", CStr::from_ptr((*parser).problem) ); let error = if (*parser).problem_mark.line != 0 || (*parser).problem_mark.column != 0 { format!( "{}\nLine: {} Column: {}", error, ((*parser).problem_mark.line).wrapping_add(1), ((*parser).problem_mark.column).wrapping_add(1), ) } else { error }; yaml_parser_delete(parser); return Err(Error::msg(error)); } let type_: YamlEventTypeT = (*event).type_; match type_ { YamlNoEvent => writeln!(stdout, "???")?, YamlStreamStartEvent => writeln!(stdout, "+STR")?, YamlStreamEndEvent => writeln!(stdout, "-STR")?, YamlDocumentStartEvent => { write!(stdout, "+DOC")?; if !(*event).data.document_start.implicit { write!(stdout, " ---")?; } writeln!(stdout)?; } YamlDocumentEndEvent => { write!(stdout, "-DOC")?; if !(*event).data.document_end.implicit { write!(stdout, " ...")?; } writeln!(stdout)?; } YamlMappingStartEvent => { write!(stdout, "+MAP")?; if !(*event).data.mapping_start.anchor.is_null() { write!( stdout, " &{}", CStr::from_ptr( (*event).data.mapping_start.anchor as *const i8 ), )?; } if !(*event).data.mapping_start.tag.is_null() { write!( stdout, " <{}>", CStr::from_ptr( (*event).data.mapping_start.tag as *const i8 ), )?; } writeln!(stdout)?; } YamlMappingEndEvent => writeln!(stdout, "-MAP")?, YamlSequenceStartEvent => { write!(stdout, "+SEQ")?; if !(*event).data.sequence_start.anchor.is_null() { write!( stdout, " &{}", CStr::from_ptr( (*event).data.sequence_start.anchor as *const i8 ), )?; } if !(*event).data.sequence_start.tag.is_null() { write!( stdout, " <{}>", CStr::from_ptr( (*event).data.sequence_start.tag as *const i8 ), )?; } writeln!(stdout)?; } YamlSequenceEndEvent => writeln!(stdout, "-SEQ")?, YamlScalarEvent => { write!(stdout, "=VAL")?; if !(*event).data.scalar.anchor.is_null() { write!( stdout, " &{}", CStr::from_ptr( (*event).data.scalar.anchor as *const i8 ), )?; } if !(*event).data.scalar.tag.is_null() { write!( stdout, " <{}>", CStr::from_ptr( (*event).data.scalar.tag as *const i8 ), )?; } stdout.write_all(match (*event).data.scalar.style { YamlPlainScalarStyle => b" :", YamlSingleQuotedScalarStyle => b" '", YamlDoubleQuotedScalarStyle => b" \"", YamlLiteralScalarStyle => b" |", YamlFoldedScalarStyle => b" >", _ => { return Err(Error::msg("Unknown scalar style")) } })?; print_escaped( stdout, (*event).data.scalar.value, (*event).data.scalar.length, )?; writeln!(stdout)?; } YamlAliasEvent => writeln!( stdout, "=ALI *{}", CStr::from_ptr((*event).data.alias.anchor as *const i8), )?, _ => return Err(Error::msg("Unknown event type")), } yaml_event_delete(event); if type_ == YamlStreamEndEvent { break; } } yaml_parser_delete(parser); Ok(()) } /// Writes an escaped version of a byte slice to the given output. /// /// This function handles proper escaping of special characters and /// preserves UTF-8 encoded characters. /// /// # Safety /// /// This function is unsafe because it works with raw pointers. /// The caller must ensure that `str` points to a valid memory location /// containing at least `length` bytes. /// /// # Arguments /// /// * `stdout` - A mutable reference to a type that implements `Write`, to which the escaped output will be written. /// * `str` - A raw pointer to the start of the byte slice to be escaped. /// * `length` - The length of the byte slice. /// /// # Returns /// /// Returns `Ok(())` if writing succeeds, or an `io::Error` if any issues occur during writing. unsafe fn print_escaped( stdout: &mut dyn Write, str: *const u8, length: u64, ) -> io::Result<()> { let slice = slice::from_raw_parts(str, length as usize); let mut chars = slice.iter().peekable(); while let Some(&byte) = chars.next() { if byte >= 128 { // Start of a UTF-8 sequence stdout.write_all(slice::from_ref(&byte))?; while let Some(&&next_byte) = chars.peek() { if !(128..192).contains(&next_byte) { break; } stdout.write_all(slice::from_ref(&next_byte))?; let _ = chars.next(); } } else { let repr = match byte { b'\\' => "\\\\", b'\0' => "\\0", b'\x08' => "\\b", b'\n' => "\\n", b'\r' => "\\r", b'\t' => "\\t", _ if byte.is_ascii_graphic() || byte == b' ' => { stdout.write_all(slice::from_ref(&byte))?; continue; } _ => { write!(stdout, "\\x{:02x}", byte)?; continue; } }; stdout.write_all(repr.as_bytes())?; } } Ok(()) } /// The entry point of the program. /// /// This function processes command-line arguments, reads YAML files, /// and calls the parsing function for each file. /// /// # Returns /// /// Returns `ExitCode::SUCCESS` if all files are processed successfully, /// or `ExitCode::FAILURE` if any errors occur. fn main() -> ExitCode { let args: Vec<_> = env::args_os().skip(1).collect(); if args.is_empty() { eprintln!("Error: No input files provided."); eprintln!( "Usage: {} ...", env::args().next().unwrap_or_default() ); eprintln!("Please provide one or more YAML files to parse."); return ExitCode::FAILURE; } for arg in args { let path = Path::new(&arg); if !path.exists() { eprintln!("Error: File {:?} does not exist.", path); return ExitCode::FAILURE; } if !path.is_file() { eprintln!("Error: {:?} is not a file.", path); return ExitCode::FAILURE; } match File::open(path) { Ok(mut file) => { let mut stdout = io::stdout(); eprintln!("Processing file: {:?}", path); match unsafe { unsafe_main(&mut file, &mut stdout) } { Ok(()) => eprintln!( "Successfully processed file: {:?}", path ), Err(err) => { eprintln!( "Error processing file {:?}: {}", path, err ); eprintln!("The parser encountered an error. Please check if the file contains valid YAML."); return ExitCode::FAILURE; } } } Err(err) => { eprintln!("Error opening file {:?}: {}", path, err); eprintln!("Please check if you have the necessary permissions to read the file."); return ExitCode::FAILURE; } } } eprintln!("All files processed successfully."); ExitCode::SUCCESS } libyml-0.0.5/src/decode.rs000064400000000000000000000065001046102023000134770ustar 00000000000000// decode.rs // Manages the decoding of YAML data structures in Rust, handling the lifecycle of YAML parsers. use crate::{ libc, memory::{yaml_free, yaml_malloc}, success::{Success, OK}, yaml::{size_t, yaml_char_t}, yaml_token_delete, YamlMarkT, YamlParserStateT, YamlParserT, YamlSimpleKeyT, YamlTagDirectiveT, YamlTokenT, }; use crate::externs::memset; use core::{ mem::size_of, ptr::{self, addr_of_mut}, }; const INPUT_RAW_BUFFER_SIZE: usize = 16384; const INPUT_BUFFER_SIZE: usize = INPUT_RAW_BUFFER_SIZE * 3; // const OUTPUT_BUFFER_SIZE: usize = 16384; // const OUTPUT_RAW_BUFFER_SIZE: usize = OUTPUT_BUFFER_SIZE * 2 + 2; /// Initialize a parser. /// /// This function creates a new parser object. An application is responsible /// for destroying the object using the yaml_parser_delete() function. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to an uninitialized `YamlParserT` struct. /// - The `YamlParserT` struct must be properly aligned and have the expected memory layout. /// - The caller is responsible for properly destroying the parser object using `yaml_parser_delete`. /// pub unsafe fn yaml_parser_initialize( parser: *mut YamlParserT, ) -> Success { __assert!(!parser.is_null()); let _ = memset( parser as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); BUFFER_INIT!((*parser).raw_buffer, INPUT_RAW_BUFFER_SIZE); BUFFER_INIT!((*parser).buffer, INPUT_BUFFER_SIZE); QUEUE_INIT!((*parser).tokens, YamlTokenT); STACK_INIT!((*parser).indents, libc::c_int); STACK_INIT!((*parser).simple_keys, YamlSimpleKeyT); STACK_INIT!((*parser).states, YamlParserStateT); STACK_INIT!((*parser).marks, YamlMarkT); STACK_INIT!((*parser).tag_directives, YamlTagDirectiveT); OK } /// Destroy a parser. /// /// This function frees all memory associated with a parser object, including /// any dynamically allocated buffers, tokens, and other data structures. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - The `YamlParserT` struct and its associated data structures must have been properly initialized and their memory allocated correctly. /// - The `YamlParserT` struct and its associated data structures must be properly aligned and have the expected memory layout. /// - After calling this function, the `parser` pointer should be considered invalid and should not be used again. /// pub unsafe fn yaml_parser_delete(parser: *mut YamlParserT) { __assert!(!parser.is_null()); BUFFER_DEL!((*parser).raw_buffer); BUFFER_DEL!((*parser).buffer); while !QUEUE_EMPTY!((*parser).tokens) { yaml_token_delete(addr_of_mut!(DEQUEUE!((*parser).tokens))); } QUEUE_DEL!((*parser).tokens); STACK_DEL!((*parser).indents); STACK_DEL!((*parser).simple_keys); STACK_DEL!((*parser).states); STACK_DEL!((*parser).marks); while !STACK_EMPTY!((*parser).tag_directives) { let tag_directive = POP!((*parser).tag_directives); yaml_free(tag_directive.handle as *mut libc::c_void); yaml_free(tag_directive.prefix as *mut libc::c_void); } STACK_DEL!((*parser).tag_directives); let _ = memset( parser as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); } libyml-0.0.5/src/document.rs000064400000000000000000000734151046102023000141030ustar 00000000000000use crate::externs::{memcpy, memset, strlen}; use crate::internal::yaml_check_utf8; use crate::internal::yaml_stack_extend; use crate::memory::{yaml_free, yaml_malloc, yaml_strdup}; use crate::ops::ForceAdd; use crate::success::{Success, FAIL, OK}; use crate::yaml::{size_t, yaml_char_t}; use crate::YamlEventT; use crate::YamlEventTypeT::YamlDocumentEndEvent; use crate::YamlEventTypeT::YamlDocumentStartEvent; use crate::{ libc, PointerExt, YamlDocumentT, YamlMappingNode, YamlMappingStyleT, YamlMarkT, YamlNodeItemT, YamlNodePairT, YamlNodeT, YamlScalarNode, YamlScalarStyleT, YamlSequenceNode, YamlSequenceStyleT, YamlTagDirectiveT, YamlVersionDirectiveT, }; use core::mem::{size_of, MaybeUninit}; use core::ptr::{self, addr_of_mut}; /// Create a YAML document. /// /// This function initializes a `YamlDocumentT` struct with the provided version directive, /// tag directives, and implicit flags. It allocates memory for the document data and /// copies the provided directives. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct that can be safely written to. /// - `version_directive`, if not null, must point to a valid `YamlVersionDirectiveT` struct. /// - `tag_directives_start` and `tag_directives_end` must be valid pointers to `YamlTagDirectiveT` structs, or both must be null. /// - If `tag_directives_start` and `tag_directives_end` are not null, the range they define must contain valid `YamlTagDirectiveT` structs with non-null `handle` and `prefix` members, and the `handle` and `prefix` strings must be valid UTF-8. /// - The `YamlDocumentT`, `YamlVersionDirectiveT`, and `YamlTagDirectiveT` structs must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing the memory allocated for the document using `yaml_document_delete`. /// pub unsafe fn yaml_document_initialize( document: *mut YamlDocumentT, version_directive: *mut YamlVersionDirectiveT, tag_directives_start: *mut YamlTagDirectiveT, tag_directives_end: *mut YamlTagDirectiveT, start_implicit: bool, end_implicit: bool, ) -> Success { let current_block: u64; struct Nodes { start: *mut YamlNodeT, end: *mut YamlNodeT, top: *mut YamlNodeT, } let mut nodes = Nodes { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut version_directive_copy: *mut YamlVersionDirectiveT = ptr::null_mut::(); struct TagDirectivesCopy { start: *mut YamlTagDirectiveT, end: *mut YamlTagDirectiveT, top: *mut YamlTagDirectiveT, } let mut tag_directives_copy = TagDirectivesCopy { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut value = YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }; let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!document.is_null()); __assert!( !tag_directives_start.is_null() && !tag_directives_end.is_null() || tag_directives_start == tag_directives_end ); STACK_INIT!(nodes, YamlNodeT); if !version_directive.is_null() { version_directive_copy = yaml_malloc( size_of::() as libc::c_ulong ) as *mut YamlVersionDirectiveT; (*version_directive_copy).major = (*version_directive).major; (*version_directive_copy).minor = (*version_directive).minor; } if tag_directives_start != tag_directives_end { let mut tag_directive: *mut YamlTagDirectiveT; STACK_INIT!(tag_directives_copy, YamlTagDirectiveT); tag_directive = tag_directives_start; loop { if tag_directive == tag_directives_end { current_block = 14818589718467733107; break; } __assert!(!((*tag_directive).handle).is_null()); __assert!(!((*tag_directive).prefix).is_null()); if yaml_check_utf8( (*tag_directive).handle, strlen((*tag_directive).handle as *mut libc::c_char), ) .fail { current_block = 8142820162064489797; break; } if yaml_check_utf8( (*tag_directive).prefix, strlen((*tag_directive).prefix as *mut libc::c_char), ) .fail { current_block = 8142820162064489797; break; } value.handle = yaml_strdup((*tag_directive).handle); value.prefix = yaml_strdup((*tag_directive).prefix); if value.handle.is_null() || value.prefix.is_null() { current_block = 8142820162064489797; break; } PUSH!(tag_directives_copy, value); value.handle = ptr::null_mut::(); value.prefix = ptr::null_mut::(); tag_directive = tag_directive.wrapping_offset(1); } } else { current_block = 14818589718467733107; } if current_block != 8142820162064489797 { let _ = memset( document as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); let fresh176 = addr_of_mut!((*document).nodes.start); *fresh176 = nodes.start; let fresh177 = addr_of_mut!((*document).nodes.end); *fresh177 = nodes.end; let fresh178 = addr_of_mut!((*document).nodes.top); *fresh178 = nodes.start; let fresh179 = addr_of_mut!((*document).version_directive); *fresh179 = version_directive_copy; let fresh180 = addr_of_mut!((*document).tag_directives.start); *fresh180 = tag_directives_copy.start; let fresh181 = addr_of_mut!((*document).tag_directives.end); *fresh181 = tag_directives_copy.top; (*document).start_implicit = start_implicit; (*document).end_implicit = end_implicit; (*document).start_mark = mark; (*document).end_mark = mark; return OK; } STACK_DEL!(nodes); yaml_free(version_directive_copy as *mut libc::c_void); while !STACK_EMPTY!(tag_directives_copy) { let value = POP!(tag_directives_copy); yaml_free(value.handle as *mut libc::c_void); yaml_free(value.prefix as *mut libc::c_void); } STACK_DEL!(tag_directives_copy); yaml_free(value.handle as *mut libc::c_void); yaml_free(value.prefix as *mut libc::c_void); FAIL } /// Delete a YAML document and all its nodes. /// /// This function frees the memory allocated for a `YamlDocumentT` struct and all its associated /// nodes, including scalar values, sequences, and mappings. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - The `YamlDocumentT` struct and its associated nodes must have been properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_document_delete(document: *mut YamlDocumentT) { // Check if the document pointer is null if document.is_null() { return; // If the pointer is null, return early to avoid any dereferencing } let mut tag_directive: *mut YamlTagDirectiveT; // Proceed with deletion only if the document pointer is valid (non-null) while !STACK_EMPTY!((*document).nodes) { let mut node = POP!((*document).nodes); yaml_free(node.tag as *mut libc::c_void); match node.type_ { YamlScalarNode => { yaml_free(node.data.scalar.value as *mut libc::c_void); } YamlSequenceNode => { STACK_DEL!(node.data.sequence.items); } YamlMappingNode => { STACK_DEL!(node.data.mapping.pairs); } _ => { __assert!(false); } } } STACK_DEL!((*document).nodes); yaml_free((*document).version_directive as *mut libc::c_void); // Handle tag directives tag_directive = (*document).tag_directives.start; while tag_directive != (*document).tag_directives.end { yaml_free((*tag_directive).handle as *mut libc::c_void); yaml_free((*tag_directive).prefix as *mut libc::c_void); tag_directive = tag_directive.wrapping_offset(1); } yaml_free((*document).tag_directives.start as *mut libc::c_void); // Clear the memory of the document structure itself let _ = memset( document as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); } /// Get a node of a YAML document. /// /// This function returns a pointer to the node at the specified `index` in the document's node /// stack. The pointer returned by this function is valid until any of the functions modifying the /// document are called. /// /// Returns the node object or NULL if `index` is out of range. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `index` must be a valid index within the range of nodes in the `YamlDocumentT` struct. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// - The caller must not modify or free the returned pointer, as it is owned by the `YamlDocumentT` struct. /// pub unsafe fn yaml_document_get_node( document: *mut YamlDocumentT, index: libc::c_int, ) -> *mut YamlNodeT { __assert!(!document.is_null()); if index > 0 && (*document).nodes.start.wrapping_offset(index as isize) <= (*document).nodes.top { return (*document) .nodes .start .wrapping_offset(index as isize) .wrapping_offset(-1_isize); } ptr::null_mut::() } /// Get the root of a YAML document node. /// /// This function returns a pointer to the root node of the YAML document. The root object is the /// first object added to the document. /// /// The pointer returned by this function is valid until any of the functions modifying the /// document are called. /// /// An empty document produced by the parser signifies the end of a YAML stream. /// /// Returns the node object or NULL if the document is empty. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// - The caller must not modify or free the returned pointer, as it is owned by the `YamlDocumentT` struct. /// pub unsafe fn yaml_document_get_root_node( document: *mut YamlDocumentT, ) -> *mut YamlNodeT { __assert!(!document.is_null()); if (*document).nodes.top != (*document).nodes.start { return (*document).nodes.start; } ptr::null_mut::() } /// Create a SCALAR node and attach it to the document. /// /// This function creates a new SCALAR node with the provided `tag`, `value`, and `style`, and /// adds it to the document's node stack. /// /// The `style` argument may be ignored by the emitter. /// /// Returns the node id or 0 on error. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `value` must be a valid, non-null pointer to a null-terminated UTF-8 string. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing the memory allocated for the document using `yaml_document_delete`. /// #[must_use] pub unsafe fn yaml_document_add_scalar( document: *mut YamlDocumentT, mut tag: *const yaml_char_t, value: *const yaml_char_t, mut length: libc::c_int, style: YamlScalarStyleT, ) -> libc::c_int { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); let mut value_copy: *mut yaml_char_t = ptr::null_mut::(); let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); __assert!(!document.is_null()); __assert!(!value.is_null()); if tag.is_null() { tag = b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char as *mut yaml_char_t; } if yaml_check_utf8(tag, strlen(tag as *mut libc::c_char)).ok { tag_copy = yaml_strdup(tag); if !tag_copy.is_null() { if length < 0 { length = strlen(value as *mut libc::c_char) as libc::c_int; } if yaml_check_utf8(value, length as size_t).ok { value_copy = yaml_malloc(length.force_add(1) as size_t) as *mut yaml_char_t; let _ = memcpy( value_copy as *mut libc::c_void, value as *const libc::c_void, length as libc::c_ulong, ); *value_copy.wrapping_offset(length as isize) = b'\0'; let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlScalarNode; (*node).tag = tag_copy; (*node).start_mark = mark; (*node).end_mark = mark; (*node).data.scalar.value = value_copy; (*node).data.scalar.length = length as size_t; (*node).data.scalar.style = style; PUSH!((*document).nodes, *node); return (*document) .nodes .top .c_offset_from((*document).nodes.start) as libc::c_int; } } } yaml_free(tag_copy as *mut libc::c_void); yaml_free(value_copy as *mut libc::c_void); 0 } /// Create a SEQUENCE node and attach it to the document. /// /// This function creates a new SEQUENCE node with the provided `tag` and `style`, and adds it to /// the document's node stack. /// /// The `style` argument may be ignored by the emitter. /// /// Returns the node id or 0 on error. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing the memory allocated for the document using `yaml_document_delete`. /// #[must_use] pub unsafe fn yaml_document_add_sequence( document: *mut YamlDocumentT, mut tag: *const yaml_char_t, style: YamlSequenceStyleT, ) -> libc::c_int { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); struct Items { start: *mut YamlNodeItemT, end: *mut YamlNodeItemT, top: *mut YamlNodeItemT, } let mut items = Items { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); __assert!(!document.is_null()); if tag.is_null() { tag = b"tag:yaml.org,2002:seq\0" as *const u8 as *const libc::c_char as *mut yaml_char_t; } if yaml_check_utf8(tag, strlen(tag as *mut libc::c_char)).ok { tag_copy = yaml_strdup(tag); if !tag_copy.is_null() { STACK_INIT!(items, YamlNodeItemT); let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlSequenceNode; (*node).tag = tag_copy; (*node).start_mark = mark; (*node).end_mark = mark; (*node).data.sequence.items.start = items.start; (*node).data.sequence.items.end = items.end; (*node).data.sequence.items.top = items.start; (*node).data.sequence.style = style; PUSH!((*document).nodes, *node); return (*document) .nodes .top .c_offset_from((*document).nodes.start) as libc::c_int; } } STACK_DEL!(items); yaml_free(tag_copy as *mut libc::c_void); 0 } /// Create a MAPPING node and attach it to the document. /// /// This function creates a new MAPPING node with the provided `tag` and `style`, and adds it to /// the document's node stack. /// /// The `style` argument may be ignored by the emitter. /// /// Returns the node id or 0 on error. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `tag`, if not null, must be a valid pointer to a null-terminated UTF-8 string. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing the memory allocated for the document using `yaml_document_delete`. /// #[must_use] pub unsafe fn yaml_document_add_mapping( document: *mut YamlDocumentT, mut tag: *const yaml_char_t, style: YamlMappingStyleT, ) -> libc::c_int { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut tag_copy: *mut yaml_char_t = ptr::null_mut::(); struct Pairs { start: *mut YamlNodePairT, end: *mut YamlNodePairT, top: *mut YamlNodePairT, } let mut pairs = Pairs { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); __assert!(!document.is_null()); if tag.is_null() { tag = b"tag:yaml.org,2002:map\0" as *const u8 as *const libc::c_char as *mut yaml_char_t; } if yaml_check_utf8(tag, strlen(tag as *mut libc::c_char)).ok { tag_copy = yaml_strdup(tag); if !tag_copy.is_null() { STACK_INIT!(pairs, YamlNodePairT); let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlMappingNode; (*node).tag = tag_copy; (*node).start_mark = mark; (*node).end_mark = mark; (*node).data.mapping.pairs.start = pairs.start; (*node).data.mapping.pairs.end = pairs.end; (*node).data.mapping.pairs.top = pairs.start; (*node).data.mapping.style = style; PUSH!((*document).nodes, *node); return (*document) .nodes .top .c_offset_from((*document).nodes.start) as libc::c_int; } } STACK_DEL!(pairs); yaml_free(tag_copy as *mut libc::c_void); 0 } /// Add an item to a SEQUENCE node. /// /// This function adds a node with the given `item` id to the sequence node with the given /// `sequence` id in the document. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `sequence` must be a valid index within the range of nodes in the `YamlDocumentT` struct, and the node at that index must be a `YamlSequenceNode`. /// - `item` must be a valid index within the range of nodes in the `YamlDocumentT` struct. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_document_append_sequence_item( document: *mut YamlDocumentT, sequence: libc::c_int, item: libc::c_int, ) -> Success { __assert!(!document.is_null()); __assert!( sequence > 0 && ((*document).nodes.start) .wrapping_offset(sequence as isize) <= (*document).nodes.top ); __assert!( (*((*document).nodes.start) .wrapping_offset((sequence - 1) as isize)) .type_ == YamlSequenceNode ); __assert!( item > 0 && ((*document).nodes.start).wrapping_offset(item as isize) <= (*document).nodes.top ); PUSH!( (*((*document).nodes.start) .wrapping_offset((sequence - 1) as isize)) .data .sequence .items, item ); OK } /// Add a pair of a key and a value to a MAPPING node. /// /// This function adds a key-value pair to the mapping node with the given `mapping` id in the /// document. The `key` and `value` arguments are the ids of the nodes to be used as the key and /// value, respectively. /// /// # Safety /// /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct. /// - `mapping` must be a valid index within the range of nodes in the `YamlDocumentT` struct, and the node at that index must be a `YamlMappingNode`. /// - `key` and `value` must be valid indices within the range of nodes in the `YamlDocumentT` struct. /// - The `YamlDocumentT` struct and its associated nodes must be properly initialized and their memory allocated correctly. /// - The `YamlDocumentT` struct and its associated nodes must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_document_append_mapping_pair( document: *mut YamlDocumentT, mapping: libc::c_int, key: libc::c_int, value: libc::c_int, ) -> Success { __assert!(!document.is_null()); __assert!( mapping > 0 && ((*document).nodes.start) .wrapping_offset(mapping as isize) <= (*document).nodes.top ); __assert!( (*((*document).nodes.start) .wrapping_offset((mapping - 1) as isize)) .type_ == YamlMappingNode ); __assert!( key > 0 && ((*document).nodes.start).wrapping_offset(key as isize) <= (*document).nodes.top ); __assert!( value > 0 && ((*document).nodes.start) .wrapping_offset(value as isize) <= (*document).nodes.top ); let pair = YamlNodePairT { key, value }; PUSH!( (*((*document).nodes.start) .wrapping_offset((mapping - 1) as isize)) .data .mapping .pairs, pair ); OK } /// Create the DOCUMENT-END event. /// /// The `implicit` argument is considered as a stylistic parameter and may be /// ignored by the emitter. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - The `YamlEventT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_document_end_event_initialize( event: *mut YamlEventT, implicit: bool, ) -> Success { let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.document_end.implicit = implicit; OK } /// Create the DOCUMENT-START event. /// /// The `implicit` argument is considered as a stylistic parameter and may be /// ignored by the emitter. /// /// # Safety /// /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely written to. /// - `version_directive`, if not null, must point to a valid `YamlVersionDirectiveT` struct. /// - `tag_directives_start` and `tag_directives_end` must be valid pointers to `YamlTagDirectiveT` structs, or both must be null. /// - If `tag_directives_start` and `tag_directives_end` are not null, the range they define must contain valid `YamlTagDirectiveT` structs with non-null `handle` and `prefix` members, and the `handle` and `prefix` strings must be valid UTF-8. /// - The `YamlEventT`, `YamlVersionDirectiveT`, and `YamlTagDirectiveT` structs must be properly aligned and have the expected memory layout. /// - The caller is responsible for freeing any dynamically allocated memory associated with the event using `yaml_event_delete`. /// pub unsafe fn yaml_document_start_event_initialize( event: *mut YamlEventT, version_directive: *mut YamlVersionDirectiveT, tag_directives_start: *mut YamlTagDirectiveT, tag_directives_end: *mut YamlTagDirectiveT, implicit: bool, ) -> Success { let current_block: u64; let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let mut version_directive_copy: *mut YamlVersionDirectiveT = ptr::null_mut::(); struct TagDirectivesCopy { start: *mut YamlTagDirectiveT, end: *mut YamlTagDirectiveT, top: *mut YamlTagDirectiveT, } let mut tag_directives_copy = TagDirectivesCopy { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut value = YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }; __assert!(!event.is_null()); __assert!( !tag_directives_start.is_null() && !tag_directives_end.is_null() || tag_directives_start == tag_directives_end ); if !version_directive.is_null() { version_directive_copy = yaml_malloc( size_of::() as libc::c_ulong ) as *mut YamlVersionDirectiveT; (*version_directive_copy).major = (*version_directive).major; (*version_directive_copy).minor = (*version_directive).minor; } if tag_directives_start != tag_directives_end { let mut tag_directive: *mut YamlTagDirectiveT; STACK_INIT!(tag_directives_copy, YamlTagDirectiveT); tag_directive = tag_directives_start; loop { if tag_directive == tag_directives_end { current_block = 16203760046146113240; break; } __assert!(!((*tag_directive).handle).is_null()); __assert!(!((*tag_directive).prefix).is_null()); if yaml_check_utf8( (*tag_directive).handle, strlen((*tag_directive).handle as *mut libc::c_char), ) .fail { current_block = 14964981520188694172; break; } if yaml_check_utf8( (*tag_directive).prefix, strlen((*tag_directive).prefix as *mut libc::c_char), ) .fail { current_block = 14964981520188694172; break; } value.handle = yaml_strdup((*tag_directive).handle); value.prefix = yaml_strdup((*tag_directive).prefix); if value.handle.is_null() || value.prefix.is_null() { current_block = 14964981520188694172; break; } PUSH!(tag_directives_copy, value); value.handle = ptr::null_mut::(); value.prefix = ptr::null_mut::(); tag_directive = tag_directive.wrapping_offset(1); } } else { current_block = 16203760046146113240; } if current_block != 14964981520188694172 { let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh164 = addr_of_mut!( (*event).data.document_start.version_directive ); *fresh164 = version_directive_copy; let fresh165 = addr_of_mut!( (*event).data.document_start.tag_directives.start ); *fresh165 = tag_directives_copy.start; let fresh166 = addr_of_mut!( (*event).data.document_start.tag_directives.end ); *fresh166 = tag_directives_copy.top; (*event).data.document_start.implicit = implicit; return OK; } yaml_free(version_directive_copy as *mut libc::c_void); while !STACK_EMPTY!(tag_directives_copy) { let value = POP!(tag_directives_copy); yaml_free(value.handle as *mut libc::c_void); yaml_free(value.prefix as *mut libc::c_void); } STACK_DEL!(tag_directives_copy); yaml_free(value.handle as *mut libc::c_void); yaml_free(value.prefix as *mut libc::c_void); FAIL } libyml-0.0.5/src/dumper.rs000064400000000000000000000470041046102023000135540ustar 00000000000000use crate::externs::{memset, strcmp}; use crate::fmt::WriteToPtr; use crate::memory::yaml_free; use crate::memory::yaml_malloc; use crate::ops::ForceMul as _; use crate::success::{Success, FAIL, OK}; use crate::yaml::{ yaml_char_t, YamlAliasEvent, YamlAnchorsT, YamlAnyEncoding, YamlDocumentEndEvent, YamlDocumentStartEvent, YamlDocumentT, YamlEmitterT, YamlEventT, YamlMappingEndEvent, YamlMappingNode, YamlMappingStartEvent, YamlMarkT, YamlNodeItemT, YamlNodePairT, YamlNodeT, YamlScalarEvent, YamlScalarNode, YamlSequenceEndEvent, YamlSequenceNode, YamlSequenceStartEvent, YamlStreamEndEvent, YamlStreamStartEvent, }; use crate::{ libc, yaml_document_delete, yaml_emitter_emit, PointerExt, }; use core::mem::{size_of, MaybeUninit}; use core::ptr::{self, addr_of_mut}; /// Start a YAML stream. /// /// This function should be used before yaml_emitter_dump() is called. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must not be in an opened state. /// - The `YamlEmitterT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_open(emitter: *mut YamlEmitterT) -> Success { if emitter.is_null() { return FAIL; } // If the emitter is already opened, return FAIL if (*emitter).opened { return FAIL; } // If the emitter was previously closed, reset its state if (*emitter).closed { (*emitter).closed = false; } let mut event = MaybeUninit::::uninit(); let event_ptr = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let _ = memset( event_ptr as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event_ptr).type_ = YamlStreamStartEvent; (*event_ptr).start_mark = mark; (*event_ptr).end_mark = mark; (*event_ptr).data.stream_start.encoding = YamlAnyEncoding; if yaml_emitter_emit(emitter, event_ptr).fail { return FAIL; } (*emitter).opened = true; (*emitter).closed = false; OK } /// Finish a YAML stream. /// /// This function should be used after yaml_emitter_dump() is called. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - The `YamlEmitterT` struct must be in an opened state and not already closed. /// - The `YamlEmitterT` struct must be properly aligned and have the expected memory layout. /// pub unsafe fn yaml_emitter_close( emitter: *mut YamlEmitterT, ) -> Success { if emitter.is_null() { return FAIL; } // If the emitter is not opened, we don't need to close it if !(*emitter).opened { return OK; } // If the emitter is already closed, we don't need to close it again if (*emitter).closed { return OK; } let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlStreamEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; if yaml_emitter_emit(emitter, event).fail { return FAIL; } (*emitter).closed = true; (*emitter).opened = false; OK } /// Emit a YAML document. /// /// The document object may be generated using the yaml_parser_load() function or /// the yaml_document_initialize() function. The emitter takes the /// responsibility for the document object and destroys its content after it is /// emitted. The document object is destroyed even if the function fails. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct that can be safely read from and will be destroyed by the function. /// - The `YamlEmitterT` and `YamlDocumentT` structs must be properly aligned and have the expected memory layout. /// - The `YamlEmitterT` struct must be in a valid state to emit the provided document. /// pub unsafe fn yaml_emitter_dump( emitter: *mut YamlEmitterT, document: *mut YamlDocumentT, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; __assert!(!emitter.is_null()); __assert!(!document.is_null()); let fresh0 = addr_of_mut!((*emitter).document); *fresh0 = document; if !(*emitter).opened && yaml_emitter_open(emitter).fail { return FAIL; } if STACK_EMPTY!((*document).nodes) { if yaml_emitter_close(emitter).ok { yaml_emitter_delete_document_and_anchors(emitter); return OK; } } else { __assert!((*emitter).opened); let fresh1 = addr_of_mut!((*emitter).anchors); *fresh1 = yaml_malloc( (size_of::() as libc::c_ulong).force_mul( (*document) .nodes .top .c_offset_from((*document).nodes.start) as libc::c_ulong, ), ) as *mut YamlAnchorsT; let _ = memset( (*emitter).anchors as *mut libc::c_void, 0, (size_of::() as libc::c_ulong).force_mul( (*document) .nodes .top .c_offset_from((*document).nodes.start) as libc::c_ulong, ), ); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.document_start.version_directive = (*document).version_directive; (*event).data.document_start.tag_directives.start = (*document).tag_directives.start; (*event).data.document_start.tag_directives.end = (*document).tag_directives.end; (*event).data.document_start.implicit = (*document).start_implicit; if yaml_emitter_emit(emitter, event).ok { yaml_emitter_anchor_node(emitter, 1); if yaml_emitter_dump_node(emitter, 1).ok { let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.document_end.implicit = (*document).end_implicit; if yaml_emitter_emit(emitter, event).ok { yaml_emitter_delete_document_and_anchors(emitter); return OK; } } } } yaml_emitter_delete_document_and_anchors(emitter); FAIL } unsafe fn yaml_emitter_delete_document_and_anchors( emitter: *mut YamlEmitterT, ) { let mut index: libc::c_int; if (*emitter).anchors.is_null() { yaml_document_delete((*emitter).document); let fresh2 = addr_of_mut!((*emitter).document); *fresh2 = ptr::null_mut::(); return; } index = 0; while (*(*emitter).document) .nodes .start .wrapping_offset(index as isize) < (*(*emitter).document).nodes.top { let mut node: YamlNodeT = *(*(*emitter).document) .nodes .start .wrapping_offset(index as isize); if !(*(*emitter).anchors.wrapping_offset(index as isize)) .serialized { yaml_free(node.tag as *mut libc::c_void); if node.type_ == YamlScalarNode { yaml_free(node.data.scalar.value as *mut libc::c_void); } } if node.type_ == YamlSequenceNode { STACK_DEL!(node.data.sequence.items); } if node.type_ == YamlMappingNode { STACK_DEL!(node.data.mapping.pairs); } index += 1; } STACK_DEL!((*(*emitter).document).nodes); yaml_free((*emitter).anchors as *mut libc::c_void); let fresh6 = addr_of_mut!((*emitter).anchors); *fresh6 = ptr::null_mut::(); (*emitter).last_anchor_id = 0; let fresh7 = addr_of_mut!((*emitter).document); *fresh7 = ptr::null_mut::(); } unsafe fn yaml_emitter_anchor_node_sub( emitter: *mut YamlEmitterT, index: libc::c_int, ) { (*((*emitter).anchors).offset((index - 1) as isize)).references += 1; if (*(*emitter).anchors.offset((index - 1) as isize)).references == 2 { (*emitter).last_anchor_id += 1; (*(*emitter).anchors.offset((index - 1) as isize)).anchor = (*emitter).last_anchor_id; } } unsafe fn yaml_emitter_anchor_node( emitter: *mut YamlEmitterT, index: libc::c_int, ) { let node: *mut YamlNodeT = (*(*emitter).document) .nodes .start .wrapping_offset(index as isize) .wrapping_offset(-1_isize); let mut item: *mut YamlNodeItemT; let mut pair: *mut YamlNodePairT; let fresh8 = addr_of_mut!( (*((*emitter).anchors).wrapping_offset((index - 1) as isize)) .references ); *fresh8 += 1; if (*(*emitter).anchors.wrapping_offset((index - 1) as isize)) .references == 1 { match (*node).type_ { YamlSequenceNode => { item = (*node).data.sequence.items.start; while item < (*node).data.sequence.items.top { yaml_emitter_anchor_node_sub(emitter, *item); item = item.wrapping_offset(1); } } YamlMappingNode => { pair = (*node).data.mapping.pairs.start; while pair < (*node).data.mapping.pairs.top { yaml_emitter_anchor_node_sub(emitter, (*pair).key); yaml_emitter_anchor_node_sub( emitter, (*pair).value, ); pair = pair.wrapping_offset(1); } } _ => {} } } else if (*(*emitter) .anchors .wrapping_offset((index - 1) as isize)) .references == 2 { let fresh9 = addr_of_mut!((*emitter).last_anchor_id); *fresh9 += 1; (*(*emitter).anchors.wrapping_offset((index - 1) as isize)) .anchor = *fresh9; } } unsafe fn yaml_emitter_generate_anchor( _emitter: *mut YamlEmitterT, anchor_id: libc::c_int, ) -> *mut yaml_char_t { let anchor: *mut yaml_char_t = yaml_malloc(16_u64) as *mut yaml_char_t; write!(WriteToPtr::new(anchor), "id{:03}\0", anchor_id); anchor } /// Dumps a YAML node to the emitter. /// /// This function is responsible for emitting a single YAML node from a document. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to an initialized `YamlEmitterT` struct. /// - `index` must be a valid index within the YAML document associated with the emitter. /// - The caller must ensure that the node at `index` can be safely emitted without causing memory issues. pub unsafe fn yaml_emitter_dump_node( emitter: *mut YamlEmitterT, index: libc::c_int, ) -> Success { let node: *mut YamlNodeT = (*(*emitter).document) .nodes .start .wrapping_offset(index as isize) .wrapping_offset(-1_isize); let anchor_id: libc::c_int = (*(*emitter).anchors.wrapping_offset((index - 1) as isize)) .anchor; let mut anchor: *mut yaml_char_t = ptr::null_mut::(); if anchor_id != 0 { anchor = yaml_emitter_generate_anchor(emitter, anchor_id); } if (*(*emitter).anchors.wrapping_offset((index - 1) as isize)) .serialized { return yaml_emitter_dump_alias(emitter, anchor); } (*(*emitter).anchors.wrapping_offset((index - 1) as isize)) .serialized = true; match (*node).type_ { YamlScalarNode => { yaml_emitter_dump_scalar(emitter, node, anchor) } YamlSequenceNode => { yaml_emitter_dump_sequence(emitter, node, anchor) } YamlMappingNode => { yaml_emitter_dump_mapping(emitter, node, anchor) } _ => __assert!(false), } } unsafe fn yaml_emitter_dump_alias( emitter: *mut YamlEmitterT, anchor: *mut yaml_char_t, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlAliasEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.alias.anchor = anchor; yaml_emitter_emit(emitter, event) } /// Dumps a YAML scalar node to the emitter. /// /// This function handles emitting a scalar node, which is a single key-value pair. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to an initialized `YamlEmitterT` struct. /// - `node` must be a valid, non-null pointer to a `YamlNodeT` struct representing the scalar node. /// - `anchor` must be a valid, non-null pointer to a `yaml_char_t` if provided, or null if no anchor is used. /// - The caller must ensure that the node and anchor pointers are valid and properly aligned. pub unsafe fn yaml_emitter_dump_scalar( emitter: *mut YamlEmitterT, node: *mut YamlNodeT, anchor: *mut yaml_char_t, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let plain_implicit = strcmp( (*node).tag as *mut libc::c_char, b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char, ) == 0; let quoted_implicit = strcmp( (*node).tag as *mut libc::c_char, b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char, ) == 0; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlScalarEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.scalar.anchor = anchor; (*event).data.scalar.tag = (*node).tag; (*event).data.scalar.value = (*node).data.scalar.value; (*event).data.scalar.length = (*node).data.scalar.length; (*event).data.scalar.plain_implicit = plain_implicit; (*event).data.scalar.quoted_implicit = quoted_implicit; (*event).data.scalar.style = (*node).data.scalar.style; yaml_emitter_emit(emitter, event) } /// Dumps a YAML sequence node to the emitter. /// /// This function handles emitting a sequence node, which is a list of items. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to an initialized `YamlEmitterT` struct. /// - `node` must be a valid, non-null pointer to a `YamlNodeT` struct representing the sequence node. /// - `anchor` must be a valid, non-null pointer to a `yaml_char_t` if provided, or null if no anchor is used. /// - The caller must ensure that the node and anchor pointers are valid and properly aligned. /// - The sequence node must contain a valid list of items that can be safely iterated and emitted. pub unsafe fn yaml_emitter_dump_sequence( emitter: *mut YamlEmitterT, node: *mut YamlNodeT, anchor: *mut yaml_char_t, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let implicit = strcmp( (*node).tag as *mut libc::c_char, b"tag:yaml.org,2002:seq\0" as *const u8 as *const libc::c_char, ) == 0; let mut item: *mut YamlNodeItemT; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.sequence_start.anchor = anchor; (*event).data.sequence_start.tag = (*node).tag; (*event).data.sequence_start.implicit = implicit; (*event).data.sequence_start.style = (*node).data.sequence.style; if yaml_emitter_emit(emitter, event).fail { return FAIL; } item = (*node).data.sequence.items.start; while item < (*node).data.sequence.items.top { if yaml_emitter_dump_node(emitter, *item).fail { return FAIL; } item = item.wrapping_offset(1); } let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; yaml_emitter_emit(emitter, event) } /// Dumps a YAML mapping node to the emitter. /// /// This function handles emitting a mapping node, which is a set of key-value pairs. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to an initialized `YamlEmitterT` struct. /// - `node` must be a valid, non-null pointer to a `YamlNodeT` struct representing the mapping node. /// - `anchor` must be a valid, non-null pointer to a `yaml_char_t` if provided, or null if no anchor is used. /// - The caller must ensure that the node and anchor pointers are valid and properly aligned. /// - The mapping node must contain a valid set of key-value pairs that can be safely iterated and emitted. pub unsafe fn yaml_emitter_dump_mapping( emitter: *mut YamlEmitterT, node: *mut YamlNodeT, anchor: *mut yaml_char_t, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); let mark = YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }; let implicit = strcmp( (*node).tag as *mut libc::c_char, b"tag:yaml.org,2002:map\0" as *const u8 as *const libc::c_char, ) == 0; let mut pair: *mut YamlNodePairT; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingStartEvent; (*event).start_mark = mark; (*event).end_mark = mark; (*event).data.mapping_start.anchor = anchor; (*event).data.mapping_start.tag = (*node).tag; (*event).data.mapping_start.implicit = implicit; (*event).data.mapping_start.style = (*node).data.mapping.style; if yaml_emitter_emit(emitter, event).fail { return FAIL; } pair = (*node).data.mapping.pairs.start; while pair < (*node).data.mapping.pairs.top { if yaml_emitter_dump_node(emitter, (*pair).key).fail { return FAIL; } if yaml_emitter_dump_node(emitter, (*pair).value).fail { return FAIL; } pair = pair.wrapping_offset(1); } let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingEndEvent; (*event).start_mark = mark; (*event).end_mark = mark; yaml_emitter_emit(emitter, event) } libyml-0.0.5/src/emitter.rs000064400000000000000000002320151046102023000137270ustar 00000000000000use crate::externs::{strcmp, strlen, strncmp}; use crate::internal::{yaml_queue_extend, yaml_stack_extend}; use crate::memory::{yaml_free, yaml_strdup}; use crate::ops::{ForceAdd as _, ForceMul as _}; use crate::success::{Success, FAIL, OK}; use crate::yaml::{size_t, yaml_char_t, YamlStringT}; use crate::{ libc, yaml_emitter_flush, yaml_event_delete, PointerExt, YamlAliasEvent, YamlAnyBreak, YamlAnyEncoding, YamlAnyScalarStyle, YamlCrBreak, YamlCrlnBreak, YamlDocumentEndEvent, YamlDocumentStartEvent, YamlDoubleQuotedScalarStyle, YamlEmitBlockMappingFirstKeyState, YamlEmitBlockMappingKeyState, YamlEmitBlockMappingSimpleValueState, YamlEmitBlockMappingValueState, YamlEmitBlockSequenceFirstItemState, YamlEmitBlockSequenceItemState, YamlEmitDocumentContentState, YamlEmitDocumentEndState, YamlEmitDocumentStartState, YamlEmitEndState, YamlEmitFirstDocumentStartState, YamlEmitFlowMappingFirstKeyState, YamlEmitFlowMappingKeyState, YamlEmitFlowMappingSimpleValueState, YamlEmitFlowMappingValueState, YamlEmitFlowSequenceFirstItemState, YamlEmitFlowSequenceItemState, YamlEmitStreamStartState, YamlEmitterError, YamlEmitterT, YamlEventT, YamlFlowMappingStyle, YamlFlowSequenceStyle, YamlFoldedScalarStyle, YamlLiteralScalarStyle, YamlLnBreak, YamlMappingEndEvent, YamlMappingStartEvent, YamlPlainScalarStyle, YamlScalarEvent, YamlScalarStyleT, YamlSequenceEndEvent, YamlSequenceStartEvent, YamlSingleQuotedScalarStyle, YamlStreamEndEvent, YamlStreamStartEvent, YamlTagDirectiveT, YamlUtf8Encoding, YamlVersionDirectiveT, }; use core::ptr::{self, addr_of_mut}; unsafe fn flush(emitter: *mut YamlEmitterT) -> Success { if (*emitter).buffer.pointer.wrapping_offset(5_isize) < (*emitter).buffer.end { OK } else { yaml_emitter_flush(emitter) } } unsafe fn put(emitter: *mut YamlEmitterT, value: u8) -> Success { if flush(emitter).fail { return FAIL; } let fresh40 = addr_of_mut!((*emitter).buffer.pointer); let fresh41 = *fresh40; *fresh40 = (*fresh40).wrapping_offset(1); *fresh41 = value; let fresh42 = addr_of_mut!((*emitter).column); *fresh42 += 1; OK } unsafe fn put_break(emitter: *mut YamlEmitterT) -> Success { if flush(emitter).fail { return FAIL; } if (*emitter).line_break == YamlCrBreak { let fresh62 = addr_of_mut!((*emitter).buffer.pointer); let fresh63 = *fresh62; *fresh62 = (*fresh62).wrapping_offset(1); *fresh63 = b'\r'; } else if (*emitter).line_break == YamlLnBreak { let fresh64 = addr_of_mut!((*emitter).buffer.pointer); let fresh65 = *fresh64; *fresh64 = (*fresh64).wrapping_offset(1); *fresh65 = b'\n'; } else if (*emitter).line_break == YamlCrlnBreak { let fresh66 = addr_of_mut!((*emitter).buffer.pointer); let fresh67 = *fresh66; *fresh66 = (*fresh66).wrapping_offset(1); *fresh67 = b'\r'; let fresh68 = addr_of_mut!((*emitter).buffer.pointer); let fresh69 = *fresh68; *fresh68 = (*fresh68).wrapping_offset(1); *fresh69 = b'\n'; }; (*emitter).column = 0; let fresh70 = addr_of_mut!((*emitter).line); *fresh70 += 1; OK } unsafe fn write( emitter: *mut YamlEmitterT, string: *mut YamlStringT, ) -> Success { if flush(emitter).fail { return FAIL; } copy!((*emitter).buffer, *string); let fresh107 = addr_of_mut!((*emitter).column); *fresh107 += 1; OK } unsafe fn write_break( emitter: *mut YamlEmitterT, string: *mut YamlStringT, ) -> Success { if flush(emitter).fail { return FAIL; } if CHECK!(*string, b'\n') { let _ = put_break(emitter); (*string).pointer = (*string).pointer.wrapping_offset(1); } else { copy!((*emitter).buffer, *string); (*emitter).column = 0; let fresh300 = addr_of_mut!((*emitter).line); *fresh300 += 1; } OK } macro_rules! write { ($emitter:expr, $string:expr) => { write($emitter, addr_of_mut!($string)) }; } macro_rules! write_break { ($emitter:expr, $string:expr) => { write_break($emitter, addr_of_mut!($string)) }; } unsafe fn yaml_emitter_set_emitter_error( emitter: *mut YamlEmitterT, problem: *const libc::c_char, ) -> Success { (*emitter).error = YamlEmitterError; let fresh0 = addr_of_mut!((*emitter).problem); *fresh0 = problem; FAIL } /// Emit an event. /// /// The event object may be generated using the yaml_parser_parse() function. /// The emitter takes the responsibility for the event object and destroys its /// content after it is emitted. The event object is destroyed even if the /// function fails. /// /// # Safety /// /// - `emitter` must be a valid, non-null pointer to a properly initialized `YamlEmitterT` struct. /// - `event` must be a valid, non-null pointer to a `YamlEventT` struct that can be safely read from and will be destroyed by the function. /// - The `YamlEmitterT` and `YamlEventT` structs must be properly aligned and have the expected memory layout. /// - The `YamlEmitterT` struct must be in a valid state to emit the provided event. pub unsafe fn yaml_emitter_emit( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { ENQUEUE!((*emitter).events, *event); while yaml_emitter_need_more_events(emitter).fail { if yaml_emitter_analyze_event(emitter, (*emitter).events.head) .fail { return FAIL; } if yaml_emitter_state_machine(emitter, (*emitter).events.head) .fail { return FAIL; } yaml_event_delete(addr_of_mut!(DEQUEUE!((*emitter).events))); } OK } unsafe fn yaml_emitter_need_more_events( emitter: *mut YamlEmitterT, ) -> Success { let mut level: libc::c_int = 0; let mut event: *mut YamlEventT; if QUEUE_EMPTY!((*emitter).events) { return OK; } let accumulate = match (*(*emitter).events.head).type_ { YamlDocumentStartEvent => 1, YamlSequenceStartEvent => 2, YamlMappingStartEvent => 3, _ => return FAIL, }; if (*emitter).events.tail.c_offset_from((*emitter).events.head) as libc::c_long > accumulate as libc::c_long { return FAIL; } event = (*emitter).events.head; while event != (*emitter).events.tail { match (*event).type_ { YamlStreamStartEvent | YamlDocumentStartEvent | YamlSequenceStartEvent | YamlMappingStartEvent => { level += 1; } YamlStreamEndEvent | YamlDocumentEndEvent | YamlSequenceEndEvent | YamlMappingEndEvent => { level -= 1; } _ => {} } if level == 0 { return FAIL; } event = event.wrapping_offset(1); } OK } unsafe fn yaml_emitter_append_tag_directive( emitter: *mut YamlEmitterT, value: YamlTagDirectiveT, allow_duplicates: bool, ) -> Success { let mut tag_directive: *mut YamlTagDirectiveT; let mut copy = YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }; tag_directive = (*emitter).tag_directives.start; while tag_directive != (*emitter).tag_directives.top { if strcmp( value.handle as *mut libc::c_char, (*tag_directive).handle as *mut libc::c_char, ) == 0 { if allow_duplicates { return OK; } return yaml_emitter_set_emitter_error( emitter, b"duplicate %TAG directive\0" as *const u8 as *const libc::c_char, ); } tag_directive = tag_directive.wrapping_offset(1); } copy.handle = yaml_strdup(value.handle); copy.prefix = yaml_strdup(value.prefix); PUSH!((*emitter).tag_directives, copy); OK } unsafe fn yaml_emitter_increase_indent( emitter: *mut YamlEmitterT, flow: bool, indentless: bool, ) { PUSH!((*emitter).indents, (*emitter).indent); if (*emitter).indent < 0 { (*emitter).indent = if flow { (*emitter).best_indent } else { 0 }; } else if !indentless { (*emitter).indent += (*emitter).best_indent; } } unsafe fn yaml_emitter_state_machine( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { match (*emitter).state { YamlEmitStreamStartState => { yaml_emitter_emit_stream_start(emitter, event) } YamlEmitFirstDocumentStartState => { yaml_emitter_emit_document_start(emitter, event, true) } YamlEmitDocumentStartState => { yaml_emitter_emit_document_start(emitter, event, false) } YamlEmitDocumentContentState => { yaml_emitter_emit_document_content(emitter, event) } YamlEmitDocumentEndState => { yaml_emitter_emit_document_end(emitter, event) } YamlEmitFlowSequenceFirstItemState => { yaml_emitter_emit_flow_sequence_item(emitter, event, true) } YamlEmitFlowSequenceItemState => { yaml_emitter_emit_flow_sequence_item(emitter, event, false) } YamlEmitFlowMappingFirstKeyState => { yaml_emitter_emit_flow_mapping_key(emitter, event, true) } YamlEmitFlowMappingKeyState => { yaml_emitter_emit_flow_mapping_key(emitter, event, false) } YamlEmitFlowMappingSimpleValueState => { yaml_emitter_emit_flow_mapping_value(emitter, event, true) } YamlEmitFlowMappingValueState => { yaml_emitter_emit_flow_mapping_value(emitter, event, false) } YamlEmitBlockSequenceFirstItemState => { yaml_emitter_emit_block_sequence_item(emitter, event, true) } YamlEmitBlockSequenceItemState => { yaml_emitter_emit_block_sequence_item(emitter, event, false) } YamlEmitBlockMappingFirstKeyState => { yaml_emitter_emit_block_mapping_key(emitter, event, true) } YamlEmitBlockMappingKeyState => { yaml_emitter_emit_block_mapping_key(emitter, event, false) } YamlEmitBlockMappingSimpleValueState => { yaml_emitter_emit_block_mapping_value(emitter, event, true) } YamlEmitBlockMappingValueState => { yaml_emitter_emit_block_mapping_value(emitter, event, false) } YamlEmitEndState => yaml_emitter_set_emitter_error( emitter, b"expected nothing after STREAM-END\0" as *const u8 as *const libc::c_char, ), } } unsafe fn yaml_emitter_emit_stream_start( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { (*emitter).open_ended = 0; if (*event).type_ == YamlStreamStartEvent { if (*emitter).encoding == YamlAnyEncoding { (*emitter).encoding = (*event).data.stream_start.encoding; } if (*emitter).encoding == YamlAnyEncoding { (*emitter).encoding = YamlUtf8Encoding; } if (*emitter).best_indent < 2 || (*emitter).best_indent > 9 { (*emitter).best_indent = 2; } if (*emitter).best_width >= 0 && (*emitter).best_width <= (*emitter).best_indent.force_mul(2) { (*emitter).best_width = 80; } if (*emitter).best_width < 0 { (*emitter).best_width = libc::c_int::MAX; } if (*emitter).line_break == YamlAnyBreak { (*emitter).line_break = YamlLnBreak; } (*emitter).indent = -1; (*emitter).line = 0; (*emitter).column = 0; (*emitter).whitespace = true; (*emitter).indention = true; if (*emitter).encoding != YamlUtf8Encoding && yaml_emitter_write_bom(emitter).fail { return FAIL; } (*emitter).state = YamlEmitFirstDocumentStartState; return OK; } yaml_emitter_set_emitter_error( emitter, b"expected STREAM-START\0" as *const u8 as *const libc::c_char, ) } unsafe fn yaml_emitter_emit_document_start( emitter: *mut YamlEmitterT, event: *mut YamlEventT, first: bool, ) -> Success { if (*event).type_ == YamlDocumentStartEvent { let mut default_tag_directives: [YamlTagDirectiveT; 3] = [ YamlTagDirectiveT { handle: b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, prefix: b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, }, YamlTagDirectiveT { handle: b"!!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, prefix: b"tag:yaml.org,2002:\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, }, YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }, ]; let mut tag_directive: *mut YamlTagDirectiveT; let mut implicit; if !(*event).data.document_start.version_directive.is_null() && yaml_emitter_analyze_version_directive( emitter, *(*event).data.document_start.version_directive, ) .fail { return FAIL; } tag_directive = (*event).data.document_start.tag_directives.start; while tag_directive != (*event).data.document_start.tag_directives.end { if yaml_emitter_analyze_tag_directive( emitter, *tag_directive, ) .fail { return FAIL; } if yaml_emitter_append_tag_directive( emitter, *tag_directive, false, ) .fail { return FAIL; } tag_directive = tag_directive.wrapping_offset(1); } tag_directive = default_tag_directives.as_mut_ptr(); while !(*tag_directive).handle.is_null() { if yaml_emitter_append_tag_directive( emitter, *tag_directive, true, ) .fail { return FAIL; } tag_directive = tag_directive.wrapping_offset(1); } implicit = (*event).data.document_start.implicit; if !first || (*emitter).canonical { implicit = false; } if (!(*event).data.document_start.version_directive.is_null() || (*event).data.document_start.tag_directives.start != (*event).data.document_start.tag_directives.end) && (*emitter).open_ended != 0 { if yaml_emitter_write_indicator( emitter, b"...\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } } (*emitter).open_ended = 0; if !(*event).data.document_start.version_directive.is_null() { implicit = false; if yaml_emitter_write_indicator( emitter, b"%YAML\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if (*(*event).data.document_start.version_directive).minor == 1 { if yaml_emitter_write_indicator( emitter, b"1.1\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } } else if yaml_emitter_write_indicator( emitter, b"1.2\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } } if (*event).data.document_start.tag_directives.start != (*event).data.document_start.tag_directives.end { implicit = false; tag_directive = (*event).data.document_start.tag_directives.start; while tag_directive != (*event).data.document_start.tag_directives.end { if yaml_emitter_write_indicator( emitter, b"%TAG\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_tag_handle( emitter, (*tag_directive).handle, strlen( (*tag_directive).handle as *mut libc::c_char, ), ) .fail { return FAIL; } if yaml_emitter_write_tag_content( emitter, (*tag_directive).prefix, strlen( (*tag_directive).prefix as *mut libc::c_char, ), true, ) .fail { return FAIL; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } tag_directive = tag_directive.wrapping_offset(1); } } if yaml_emitter_check_empty_document(emitter) { implicit = false; } if !implicit { if yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b"---\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if (*emitter).canonical && yaml_emitter_write_indent(emitter).fail { return FAIL; } } (*emitter).state = YamlEmitDocumentContentState; (*emitter).open_ended = 0; return OK; } else if (*event).type_ == YamlStreamEndEvent { if (*emitter).open_ended == 2 { if yaml_emitter_write_indicator( emitter, b"...\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } (*emitter).open_ended = 0; if yaml_emitter_write_indent(emitter).fail { return FAIL; } } if yaml_emitter_flush(emitter).fail { return FAIL; } (*emitter).state = YamlEmitEndState; return OK; } yaml_emitter_set_emitter_error( emitter, b"expected DOCUMENT-START or STREAM-END\0" as *const u8 as *const libc::c_char, ) } unsafe fn yaml_emitter_emit_document_content( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { PUSH!((*emitter).states, YamlEmitDocumentEndState); yaml_emitter_emit_node(emitter, event, true, false, false, false) } unsafe fn yaml_emitter_emit_document_end( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { if (*event).type_ == YamlDocumentEndEvent { if yaml_emitter_write_indent(emitter).fail { return FAIL; } if !(*event).data.document_end.implicit { if yaml_emitter_write_indicator( emitter, b"...\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } (*emitter).open_ended = 0; if yaml_emitter_write_indent(emitter).fail { return FAIL; } } else if (*emitter).open_ended == 0 { (*emitter).open_ended = 1; } if yaml_emitter_flush(emitter).fail { return FAIL; } (*emitter).state = YamlEmitDocumentStartState; while !STACK_EMPTY!((*emitter).tag_directives) { let tag_directive = POP!((*emitter).tag_directives); yaml_free(tag_directive.handle as *mut libc::c_void); yaml_free(tag_directive.prefix as *mut libc::c_void); } return OK; } yaml_emitter_set_emitter_error( emitter, b"expected DOCUMENT-END\0" as *const u8 as *const libc::c_char, ) } unsafe fn yaml_emitter_emit_flow_sequence_item( emitter: *mut YamlEmitterT, event: *mut YamlEventT, first: bool, ) -> Success { if first { if yaml_emitter_write_indicator( emitter, b"[\0" as *const u8 as *const libc::c_char, true, true, false, ) .fail { return FAIL; } yaml_emitter_increase_indent(emitter, true, false); let fresh12 = addr_of_mut!((*emitter).flow_level); *fresh12 += 1; } if (*event).type_ == YamlSequenceEndEvent { let fresh13 = addr_of_mut!((*emitter).flow_level); *fresh13 -= 1; (*emitter).indent = POP!((*emitter).indents); if (*emitter).canonical && !first { if yaml_emitter_write_indicator( emitter, b",\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } } if yaml_emitter_write_indicator( emitter, b"]\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } (*emitter).state = POP!((*emitter).states); return OK; } if !first && yaml_emitter_write_indicator( emitter, b",\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } if ((*emitter).canonical || (*emitter).column > (*emitter).best_width) && yaml_emitter_write_indent(emitter).fail { return FAIL; } PUSH!((*emitter).states, YamlEmitFlowSequenceItemState); yaml_emitter_emit_node(emitter, event, false, true, false, false) } unsafe fn yaml_emitter_emit_flow_mapping_key( emitter: *mut YamlEmitterT, event: *mut YamlEventT, first: bool, ) -> Success { if first { if yaml_emitter_write_indicator( emitter, b"{\0" as *const u8 as *const libc::c_char, true, true, false, ) .fail { return FAIL; } yaml_emitter_increase_indent(emitter, true, false); let fresh18 = addr_of_mut!((*emitter).flow_level); *fresh18 += 1; } if (*event).type_ == YamlMappingEndEvent { if STACK_EMPTY!((*emitter).indents) { return FAIL; } let fresh19 = addr_of_mut!((*emitter).flow_level); *fresh19 -= 1; (*emitter).indent = POP!((*emitter).indents); if (*emitter).canonical && !first { if yaml_emitter_write_indicator( emitter, b",\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } } if yaml_emitter_write_indicator( emitter, b"}\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } (*emitter).state = POP!((*emitter).states); return OK; } if !first && yaml_emitter_write_indicator( emitter, b",\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } if ((*emitter).canonical || (*emitter).column > (*emitter).best_width) && yaml_emitter_write_indent(emitter).fail { return FAIL; } if !(*emitter).canonical && yaml_emitter_check_simple_key(emitter) { PUSH!((*emitter).states, YamlEmitFlowMappingSimpleValueState); yaml_emitter_emit_node(emitter, event, false, false, true, true) } else { if yaml_emitter_write_indicator( emitter, b"?\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } PUSH!((*emitter).states, YamlEmitFlowMappingValueState); yaml_emitter_emit_node( emitter, event, false, false, true, false, ) } } unsafe fn yaml_emitter_emit_flow_mapping_value( emitter: *mut YamlEmitterT, event: *mut YamlEventT, simple: bool, ) -> Success { if simple { if yaml_emitter_write_indicator( emitter, b":\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } } else { if ((*emitter).canonical || (*emitter).column > (*emitter).best_width) && yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b":\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } } PUSH!((*emitter).states, YamlEmitFlowMappingKeyState); yaml_emitter_emit_node(emitter, event, false, false, true, false) } unsafe fn yaml_emitter_emit_block_sequence_item( emitter: *mut YamlEmitterT, event: *mut YamlEventT, first: bool, ) -> Success { if first { yaml_emitter_increase_indent( emitter, false, (*emitter).mapping_context && !(*emitter).indention, ); } if (*event).type_ == YamlSequenceEndEvent { (*emitter).indent = POP!((*emitter).indents); (*emitter).state = POP!((*emitter).states); return OK; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b"-\0" as *const u8 as *const libc::c_char, true, false, true, ) .fail { return FAIL; } PUSH!((*emitter).states, YamlEmitBlockSequenceItemState); yaml_emitter_emit_node(emitter, event, false, true, false, false) } unsafe fn yaml_emitter_emit_block_mapping_key( emitter: *mut YamlEmitterT, event: *mut YamlEventT, first: bool, ) -> Success { if first { yaml_emitter_increase_indent(emitter, false, false); } if (*event).type_ == YamlMappingEndEvent { (*emitter).indent = POP!((*emitter).indents); (*emitter).state = POP!((*emitter).states); return OK; } if yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_check_simple_key(emitter) { PUSH!((*emitter).states, YamlEmitBlockMappingSimpleValueState); yaml_emitter_emit_node(emitter, event, false, false, true, true) } else { if yaml_emitter_write_indicator( emitter, b"?\0" as *const u8 as *const libc::c_char, true, false, true, ) .fail { return FAIL; } PUSH!((*emitter).states, YamlEmitBlockMappingValueState); yaml_emitter_emit_node( emitter, event, false, false, true, false, ) } } unsafe fn yaml_emitter_emit_block_mapping_value( emitter: *mut YamlEmitterT, event: *mut YamlEventT, simple: bool, ) -> Success { if simple { if yaml_emitter_write_indicator( emitter, b":\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } } else { if yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b":\0" as *const u8 as *const libc::c_char, true, false, true, ) .fail { return FAIL; } } PUSH!((*emitter).states, YamlEmitBlockMappingKeyState); yaml_emitter_emit_node(emitter, event, false, false, true, false) } unsafe fn yaml_emitter_emit_node( emitter: *mut YamlEmitterT, event: *mut YamlEventT, root: bool, sequence: bool, mapping: bool, simple_key: bool, ) -> Success { (*emitter).root_context = root; (*emitter).sequence_context = sequence; (*emitter).mapping_context = mapping; (*emitter).simple_key_context = simple_key; match (*event).type_ { YamlAliasEvent => yaml_emitter_emit_alias(emitter, event), YamlScalarEvent => yaml_emitter_emit_scalar(emitter, event), YamlSequenceStartEvent => yaml_emitter_emit_sequence_start(emitter, event), YamlMappingStartEvent => yaml_emitter_emit_mapping_start(emitter, event), _ => yaml_emitter_set_emitter_error( emitter, b"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS\0" as *const u8 as *const libc::c_char, ), } } unsafe fn yaml_emitter_emit_alias( emitter: *mut YamlEmitterT, _event: *mut YamlEventT, ) -> Success { if yaml_emitter_process_anchor(emitter).fail { return FAIL; } if (*emitter).simple_key_context && put(emitter, b' ').fail { return FAIL; } (*emitter).state = POP!((*emitter).states); OK } unsafe fn yaml_emitter_emit_scalar( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { if yaml_emitter_select_scalar_style(emitter, event).fail { return FAIL; } if yaml_emitter_process_anchor(emitter).fail { return FAIL; } if yaml_emitter_process_tag(emitter).fail { return FAIL; } yaml_emitter_increase_indent(emitter, true, false); if yaml_emitter_process_scalar(emitter).fail { return FAIL; } (*emitter).indent = POP!((*emitter).indents); (*emitter).state = POP!((*emitter).states); OK } unsafe fn yaml_emitter_emit_sequence_start( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { if yaml_emitter_process_anchor(emitter).fail { return FAIL; } if yaml_emitter_process_tag(emitter).fail { return FAIL; } if (*emitter).flow_level != 0 || (*emitter).canonical || (*event).data.sequence_start.style == YamlFlowSequenceStyle || yaml_emitter_check_empty_sequence(emitter) { (*emitter).state = YamlEmitFlowSequenceFirstItemState; } else { (*emitter).state = YamlEmitBlockSequenceFirstItemState; } OK } unsafe fn yaml_emitter_emit_mapping_start( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { if yaml_emitter_process_anchor(emitter).fail { return FAIL; } if yaml_emitter_process_tag(emitter).fail { return FAIL; } if (*emitter).flow_level != 0 || (*emitter).canonical || (*event).data.mapping_start.style == YamlFlowMappingStyle || yaml_emitter_check_empty_mapping(emitter) { (*emitter).state = YamlEmitFlowMappingFirstKeyState; } else { (*emitter).state = YamlEmitBlockMappingFirstKeyState; } OK } unsafe fn yaml_emitter_check_empty_document( _emitter: *mut YamlEmitterT, ) -> bool { false } unsafe fn yaml_emitter_check_empty_sequence( emitter: *mut YamlEmitterT, ) -> bool { if ((*emitter).events.tail.c_offset_from((*emitter).events.head) as libc::c_long) < 2_i64 { return false; } (*(*emitter).events.head).type_ == YamlSequenceStartEvent && (*(*emitter).events.head.wrapping_offset(1_isize)).type_ == YamlSequenceEndEvent } unsafe fn yaml_emitter_check_empty_mapping( emitter: *mut YamlEmitterT, ) -> bool { if ((*emitter).events.tail.c_offset_from((*emitter).events.head) as libc::c_long) < 2_i64 { return false; } (*(*emitter).events.head).type_ == YamlMappingStartEvent && (*(*emitter).events.head.wrapping_offset(1_isize)).type_ == YamlMappingEndEvent } unsafe fn yaml_emitter_check_simple_key( emitter: *mut YamlEmitterT, ) -> bool { let event: *mut YamlEventT = (*emitter).events.head; let mut length: size_t = 0_u64; match (*event).type_ { YamlAliasEvent => { length = length.force_add((*emitter).anchor_data.anchor_length); } YamlScalarEvent => { if (*emitter).scalar_data.multiline { return false; } length = length .force_add((*emitter).anchor_data.anchor_length) .force_add((*emitter).tag_data.handle_length) .force_add((*emitter).tag_data.suffix_length) .force_add((*emitter).scalar_data.length); } YamlSequenceStartEvent => { if !yaml_emitter_check_empty_sequence(emitter) { return false; } length = length .force_add((*emitter).anchor_data.anchor_length) .force_add((*emitter).tag_data.handle_length) .force_add((*emitter).tag_data.suffix_length); } YamlMappingStartEvent => { if !yaml_emitter_check_empty_mapping(emitter) { return false; } length = length .force_add((*emitter).anchor_data.anchor_length) .force_add((*emitter).tag_data.handle_length) .force_add((*emitter).tag_data.suffix_length); } _ => return false, } if length > 128_u64 { return false; } true } unsafe fn yaml_emitter_select_scalar_style( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { let mut style: YamlScalarStyleT = (*event).data.scalar.style; let no_tag = (*emitter).tag_data.handle.is_null() && (*emitter).tag_data.suffix.is_null(); if no_tag && !(*event).data.scalar.plain_implicit && !(*event).data.scalar.quoted_implicit { return yaml_emitter_set_emitter_error( emitter, b"neither tag nor implicit flags are specified\0" as *const u8 as *const libc::c_char, ); } if style == YamlAnyScalarStyle { style = YamlPlainScalarStyle; } if (*emitter).canonical { style = YamlDoubleQuotedScalarStyle; } if (*emitter).simple_key_context && (*emitter).scalar_data.multiline { style = YamlDoubleQuotedScalarStyle; } if style == YamlPlainScalarStyle { if (*emitter).flow_level != 0 && !(*emitter).scalar_data.flow_plain_allowed || (*emitter).flow_level == 0 && !(*emitter).scalar_data.block_plain_allowed { style = YamlSingleQuotedScalarStyle; } if (*emitter).scalar_data.length == 0 && ((*emitter).flow_level != 0 || (*emitter).simple_key_context) { style = YamlSingleQuotedScalarStyle; } if no_tag && !(*event).data.scalar.plain_implicit { style = YamlSingleQuotedScalarStyle; } } if style == YamlSingleQuotedScalarStyle && !(*emitter).scalar_data.single_quoted_allowed { style = YamlDoubleQuotedScalarStyle; } if (style == YamlLiteralScalarStyle || style == YamlFoldedScalarStyle) && (!(*emitter).scalar_data.block_allowed || (*emitter).flow_level != 0 || (*emitter).simple_key_context) { style = YamlDoubleQuotedScalarStyle; } if no_tag && !(*event).data.scalar.quoted_implicit && style != YamlPlainScalarStyle { let fresh46 = addr_of_mut!((*emitter).tag_data.handle); *fresh46 = b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t; (*emitter).tag_data.handle_length = 1_u64; } (*emitter).scalar_data.style = style; OK } unsafe fn yaml_emitter_process_anchor( emitter: *mut YamlEmitterT, ) -> Success { if (*emitter).anchor_data.anchor.is_null() { return OK; } if yaml_emitter_write_indicator( emitter, if (*emitter).anchor_data.alias { b"*\0" as *const u8 as *const libc::c_char } else { b"&\0" as *const u8 as *const libc::c_char }, true, false, false, ) .fail { return FAIL; } yaml_emitter_write_anchor( emitter, (*emitter).anchor_data.anchor, (*emitter).anchor_data.anchor_length, ) } unsafe fn yaml_emitter_process_tag( emitter: *mut YamlEmitterT, ) -> Success { if (*emitter).tag_data.handle.is_null() && (*emitter).tag_data.suffix.is_null() { return OK; } if !(*emitter).tag_data.handle.is_null() { if yaml_emitter_write_tag_handle( emitter, (*emitter).tag_data.handle, (*emitter).tag_data.handle_length, ) .fail { return FAIL; } if !(*emitter).tag_data.suffix.is_null() && yaml_emitter_write_tag_content( emitter, (*emitter).tag_data.suffix, (*emitter).tag_data.suffix_length, false, ) .fail { return FAIL; } } else { if yaml_emitter_write_indicator( emitter, b"!<\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_tag_content( emitter, (*emitter).tag_data.suffix, (*emitter).tag_data.suffix_length, false, ) .fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b">\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } } OK } unsafe fn yaml_emitter_process_scalar( emitter: *mut YamlEmitterT, ) -> Success { match (*emitter).scalar_data.style { YamlPlainScalarStyle => { return yaml_emitter_write_plain_scalar( emitter, (*emitter).scalar_data.value, (*emitter).scalar_data.length, !(*emitter).simple_key_context, ); } YamlSingleQuotedScalarStyle => { return yaml_emitter_write_single_quoted_scalar( emitter, (*emitter).scalar_data.value, (*emitter).scalar_data.length, !(*emitter).simple_key_context, ); } YamlDoubleQuotedScalarStyle => { return yaml_emitter_write_double_quoted_scalar( emitter, (*emitter).scalar_data.value, (*emitter).scalar_data.length, !(*emitter).simple_key_context, ); } YamlLiteralScalarStyle => { return yaml_emitter_write_literal_scalar( emitter, (*emitter).scalar_data.value, (*emitter).scalar_data.length, ); } YamlFoldedScalarStyle => { return yaml_emitter_write_folded_scalar( emitter, (*emitter).scalar_data.value, (*emitter).scalar_data.length, ); } _ => {} } FAIL } unsafe fn yaml_emitter_analyze_version_directive( emitter: *mut YamlEmitterT, version_directive: YamlVersionDirectiveT, ) -> Success { if version_directive.major != 1 || version_directive.minor != 1 && version_directive.minor != 2 { return yaml_emitter_set_emitter_error( emitter, b"incompatible %YAML directive\0" as *const u8 as *const libc::c_char, ); } OK } unsafe fn yaml_emitter_analyze_tag_directive( emitter: *mut YamlEmitterT, tag_directive: YamlTagDirectiveT, ) -> Success { let handle_length: size_t = strlen(tag_directive.handle as *mut libc::c_char); let prefix_length: size_t = strlen(tag_directive.prefix as *mut libc::c_char); let mut handle = STRING_ASSIGN!(tag_directive.handle, handle_length); let prefix = STRING_ASSIGN!(tag_directive.prefix, prefix_length); if handle.start == handle.end { return yaml_emitter_set_emitter_error( emitter, b"tag handle must not be empty\0" as *const u8 as *const libc::c_char, ); } if *handle.start != b'!' { return yaml_emitter_set_emitter_error( emitter, b"tag handle must start with '!'\0" as *const u8 as *const libc::c_char, ); } if *handle.end.wrapping_offset(-1_isize) != b'!' { return yaml_emitter_set_emitter_error( emitter, b"tag handle must end with '!'\0" as *const u8 as *const libc::c_char, ); } handle.pointer = handle.pointer.wrapping_offset(1); while handle.pointer < handle.end.wrapping_offset(-1_isize) { if !IS_ALPHA!(handle) { return yaml_emitter_set_emitter_error( emitter, b"tag handle must contain alphanumerical characters only\0" as *const u8 as *const libc::c_char, ); } MOVE!(handle); } if prefix.start == prefix.end { return yaml_emitter_set_emitter_error( emitter, b"tag prefix must not be empty\0" as *const u8 as *const libc::c_char, ); } OK } unsafe fn yaml_emitter_analyze_anchor( emitter: *mut YamlEmitterT, anchor: *mut yaml_char_t, alias: bool, ) -> Success { let anchor_length: size_t = strlen(anchor as *mut libc::c_char); let mut string = STRING_ASSIGN!(anchor, anchor_length); if string.start == string.end { return yaml_emitter_set_emitter_error( emitter, if alias { b"alias value must not be empty\0" as *const u8 as *const libc::c_char } else { b"anchor value must not be empty\0" as *const u8 as *const libc::c_char }, ); } while string.pointer != string.end { if !IS_ALPHA!(string) { return yaml_emitter_set_emitter_error( emitter, if alias { b"alias value must contain alphanumerical characters only\0" as *const u8 as *const libc::c_char } else { b"anchor value must contain alphanumerical characters only\0" as *const u8 as *const libc::c_char }, ); } MOVE!(string); } let fresh47 = addr_of_mut!((*emitter).anchor_data.anchor); *fresh47 = string.start; (*emitter).anchor_data.anchor_length = string.end.c_offset_from(string.start) as size_t; (*emitter).anchor_data.alias = alias; OK } unsafe fn yaml_emitter_analyze_tag( emitter: *mut YamlEmitterT, tag: *mut yaml_char_t, ) -> Success { let mut tag_directive: *mut YamlTagDirectiveT; let tag_length: size_t = strlen(tag as *mut libc::c_char); let string = STRING_ASSIGN!(tag, tag_length); if string.start == string.end { return yaml_emitter_set_emitter_error( emitter, b"tag value must not be empty\0" as *const u8 as *const libc::c_char, ); } tag_directive = (*emitter).tag_directives.start; while tag_directive != (*emitter).tag_directives.top { let prefix_length: size_t = strlen((*tag_directive).prefix as *mut libc::c_char); if prefix_length < string.end.c_offset_from(string.start) as size_t && strncmp( (*tag_directive).prefix as *mut libc::c_char, string.start as *mut libc::c_char, prefix_length, ) == 0 { let fresh48 = addr_of_mut!((*emitter).tag_data.handle); *fresh48 = (*tag_directive).handle; (*emitter).tag_data.handle_length = strlen((*tag_directive).handle as *mut libc::c_char); let fresh49 = addr_of_mut!((*emitter).tag_data.suffix); *fresh49 = string.start.wrapping_offset(prefix_length as isize); (*emitter).tag_data.suffix_length = (string.end.c_offset_from(string.start) as libc::c_ulong) .wrapping_sub(prefix_length); return OK; } tag_directive = tag_directive.wrapping_offset(1); } let fresh50 = addr_of_mut!((*emitter).tag_data.suffix); *fresh50 = string.start; (*emitter).tag_data.suffix_length = string.end.c_offset_from(string.start) as size_t; OK } unsafe fn yaml_emitter_analyze_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, ) -> Success { let mut block_indicators = false; let mut flow_indicators = false; let mut line_breaks = false; let mut special_characters = false; let mut leading_space = false; let mut leading_break = false; let mut trailing_space = false; let mut trailing_break = false; let mut break_space = false; let mut space_break = false; let mut preceded_by_whitespace; let mut followed_by_whitespace; let mut previous_space = false; let mut previous_break = false; let mut string = STRING_ASSIGN!(value, length); let fresh51 = addr_of_mut!((*emitter).scalar_data.value); *fresh51 = value; (*emitter).scalar_data.length = length; if string.start == string.end { (*emitter).scalar_data.multiline = false; (*emitter).scalar_data.flow_plain_allowed = false; (*emitter).scalar_data.block_plain_allowed = true; (*emitter).scalar_data.single_quoted_allowed = true; (*emitter).scalar_data.block_allowed = false; return OK; } if CHECK_AT!(string, b'-', 0) && CHECK_AT!(string, b'-', 1) && CHECK_AT!(string, b'-', 2) || CHECK_AT!(string, b'.', 0) && CHECK_AT!(string, b'.', 1) && CHECK_AT!(string, b'.', 2) { block_indicators = true; flow_indicators = true; } preceded_by_whitespace = true; followed_by_whitespace = IS_BLANKZ_AT!(string, WIDTH!(string)); while string.pointer != string.end { if string.start == string.pointer { if CHECK!(string, b'#') || CHECK!(string, b',') || CHECK!(string, b'[') || CHECK!(string, b']') || CHECK!(string, b'{') || CHECK!(string, b'}') || CHECK!(string, b'&') || CHECK!(string, b'*') || CHECK!(string, b'!') || CHECK!(string, b'|') || CHECK!(string, b'>') || CHECK!(string, b'\'') || CHECK!(string, b'"') || CHECK!(string, b'%') || CHECK!(string, b'@') || CHECK!(string, b'`') { flow_indicators = true; block_indicators = true; } if CHECK!(string, b'?') || CHECK!(string, b':') { flow_indicators = true; if followed_by_whitespace { block_indicators = true; } } if CHECK!(string, b'-') && followed_by_whitespace { flow_indicators = true; block_indicators = true; } } else { if CHECK!(string, b',') || CHECK!(string, b'?') || CHECK!(string, b'[') || CHECK!(string, b']') || CHECK!(string, b'{') || CHECK!(string, b'}') { flow_indicators = true; } if CHECK!(string, b':') { flow_indicators = true; if followed_by_whitespace { block_indicators = true; } } if CHECK!(string, b'#') && preceded_by_whitespace { flow_indicators = true; block_indicators = true; } } if !IS_PRINTABLE!(string) || !IS_ASCII!(string) && !(*emitter).unicode { special_characters = true; } if IS_BREAK!(string) { line_breaks = true; } if IS_SPACE!(string) { if string.start == string.pointer { leading_space = true; } if string.pointer.wrapping_offset(WIDTH!(string) as isize) == string.end { trailing_space = true; } if previous_break { break_space = true; } previous_space = true; previous_break = false; } else if IS_BREAK!(string) { if string.start == string.pointer { leading_break = true; } if string.pointer.wrapping_offset(WIDTH!(string) as isize) == string.end { trailing_break = true; } if previous_space { space_break = true; } previous_space = false; previous_break = true; } else { previous_space = false; previous_break = false; } preceded_by_whitespace = IS_BLANKZ!(string); MOVE!(string); if string.pointer != string.end { followed_by_whitespace = IS_BLANKZ_AT!(string, WIDTH!(string)); } } (*emitter).scalar_data.multiline = line_breaks; (*emitter).scalar_data.flow_plain_allowed = true; (*emitter).scalar_data.block_plain_allowed = true; (*emitter).scalar_data.single_quoted_allowed = true; (*emitter).scalar_data.block_allowed = true; if leading_space || leading_break || trailing_space || trailing_break { (*emitter).scalar_data.flow_plain_allowed = false; (*emitter).scalar_data.block_plain_allowed = false; } if trailing_space { (*emitter).scalar_data.block_allowed = false; } if break_space { (*emitter).scalar_data.flow_plain_allowed = false; (*emitter).scalar_data.block_plain_allowed = false; (*emitter).scalar_data.single_quoted_allowed = false; } if space_break || special_characters { (*emitter).scalar_data.flow_plain_allowed = false; (*emitter).scalar_data.block_plain_allowed = false; (*emitter).scalar_data.single_quoted_allowed = false; (*emitter).scalar_data.block_allowed = false; } if line_breaks { (*emitter).scalar_data.flow_plain_allowed = false; (*emitter).scalar_data.block_plain_allowed = false; } if flow_indicators { (*emitter).scalar_data.flow_plain_allowed = false; } if block_indicators { (*emitter).scalar_data.block_plain_allowed = false; } OK } unsafe fn yaml_emitter_analyze_event( emitter: *mut YamlEmitterT, event: *mut YamlEventT, ) -> Success { let fresh52 = addr_of_mut!((*emitter).anchor_data.anchor); *fresh52 = ptr::null_mut::(); (*emitter).anchor_data.anchor_length = 0_u64; let fresh53 = addr_of_mut!((*emitter).tag_data.handle); *fresh53 = ptr::null_mut::(); (*emitter).tag_data.handle_length = 0_u64; let fresh54 = addr_of_mut!((*emitter).tag_data.suffix); *fresh54 = ptr::null_mut::(); (*emitter).tag_data.suffix_length = 0_u64; let fresh55 = addr_of_mut!((*emitter).scalar_data.value); *fresh55 = ptr::null_mut::(); (*emitter).scalar_data.length = 0_u64; match (*event).type_ { YamlAliasEvent => yaml_emitter_analyze_anchor( emitter, (*event).data.alias.anchor, true, ), YamlScalarEvent => { if !(*event).data.scalar.anchor.is_null() && yaml_emitter_analyze_anchor( emitter, (*event).data.scalar.anchor, false, ) .fail { return FAIL; } if !(*event).data.scalar.tag.is_null() && ((*emitter).canonical || !(*event).data.scalar.plain_implicit && !(*event).data.scalar.quoted_implicit) && yaml_emitter_analyze_tag( emitter, (*event).data.scalar.tag, ) .fail { return FAIL; } yaml_emitter_analyze_scalar( emitter, (*event).data.scalar.value, (*event).data.scalar.length, ) } YamlSequenceStartEvent => { if !(*event).data.sequence_start.anchor.is_null() && yaml_emitter_analyze_anchor( emitter, (*event).data.sequence_start.anchor, false, ) .fail { return FAIL; } if !(*event).data.sequence_start.tag.is_null() && ((*emitter).canonical || !(*event).data.sequence_start.implicit) && yaml_emitter_analyze_tag( emitter, (*event).data.sequence_start.tag, ) .fail { return FAIL; } OK } YamlMappingStartEvent => { if !(*event).data.mapping_start.anchor.is_null() && yaml_emitter_analyze_anchor( emitter, (*event).data.mapping_start.anchor, false, ) .fail { return FAIL; } if !(*event).data.mapping_start.tag.is_null() && ((*emitter).canonical || !(*event).data.mapping_start.implicit) && yaml_emitter_analyze_tag( emitter, (*event).data.mapping_start.tag, ) .fail { return FAIL; } OK } _ => OK, } } unsafe fn yaml_emitter_write_bom( emitter: *mut YamlEmitterT, ) -> Success { if flush(emitter).fail { return FAIL; } let fresh56 = addr_of_mut!((*emitter).buffer.pointer); let fresh57 = *fresh56; *fresh56 = (*fresh56).wrapping_offset(1); *fresh57 = b'\xEF'; let fresh58 = addr_of_mut!((*emitter).buffer.pointer); let fresh59 = *fresh58; *fresh58 = (*fresh58).wrapping_offset(1); *fresh59 = b'\xBB'; let fresh60 = addr_of_mut!((*emitter).buffer.pointer); let fresh61 = *fresh60; *fresh60 = (*fresh60).wrapping_offset(1); *fresh61 = b'\xBF'; OK } unsafe fn yaml_emitter_write_indent( emitter: *mut YamlEmitterT, ) -> Success { let indent: libc::c_int = if (*emitter).indent >= 0 { (*emitter).indent } else { 0 }; if (!(*emitter).indention || (*emitter).column > indent || (*emitter).column == indent && !(*emitter).whitespace) && put_break(emitter).fail { return FAIL; } if (*emitter).column < indent { loop { if put(emitter, b' ').fail { return FAIL; } if (*emitter).column >= indent { break; } } } (*emitter).whitespace = true; (*emitter).indention = true; OK } unsafe fn yaml_emitter_write_indicator( emitter: *mut YamlEmitterT, indicator: *const libc::c_char, need_whitespace: bool, is_whitespace: bool, is_indention: bool, ) -> Success { let indicator_length: size_t = strlen(indicator); let mut string = STRING_ASSIGN!(indicator as *mut yaml_char_t, indicator_length); if need_whitespace && !(*emitter).whitespace && put(emitter, b' ').fail { return FAIL; } while string.pointer != string.end { if write!(emitter, string).fail { return FAIL; } } (*emitter).whitespace = is_whitespace; (*emitter).indention = (*emitter).indention && is_indention; OK } unsafe fn yaml_emitter_write_anchor( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, ) -> Success { let mut string = STRING_ASSIGN!(value, length); while string.pointer != string.end { if write!(emitter, string).fail { return FAIL; } } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_tag_handle( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, ) -> Success { let mut string = STRING_ASSIGN!(value, length); if !(*emitter).whitespace && put(emitter, b' ').fail { return FAIL; } while string.pointer != string.end { if write!(emitter, string).fail { return FAIL; } } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_tag_content( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, need_whitespace: bool, ) -> Success { let mut string = STRING_ASSIGN!(value, length); if need_whitespace && !(*emitter).whitespace && put(emitter, b' ').fail { return FAIL; } while string.pointer != string.end { if IS_ALPHA!(string) || CHECK!(string, b';') || CHECK!(string, b'/') || CHECK!(string, b'?') || CHECK!(string, b':') || CHECK!(string, b'@') || CHECK!(string, b'&') || CHECK!(string, b'=') || CHECK!(string, b'+') || CHECK!(string, b'$') || CHECK!(string, b',') || CHECK!(string, b'_') || CHECK!(string, b'.') || CHECK!(string, b'~') || CHECK!(string, b'*') || CHECK!(string, b'\'') || CHECK!(string, b'(') || CHECK!(string, b')') || CHECK!(string, b'[') || CHECK!(string, b']') { if write!(emitter, string).fail { return FAIL; } } else { let mut width = WIDTH!(string); loop { let fresh207 = width; width -= 1; if fresh207 == 0 { break; } let fresh208 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); let value = *fresh208; if put(emitter, b'%').fail { return FAIL; } if put( emitter, (value >> 4).force_add(if (value >> 4) < 10 { b'0' } else { b'A' - 10 }), ) .fail { return FAIL; } if put( emitter, (value & 0x0F).force_add(if (value & 0x0F) < 10 { b'0' } else { b'A' - 10 }), ) .fail { return FAIL; } } } } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_plain_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, allow_breaks: bool, ) -> Success { let mut spaces = false; let mut breaks = false; let mut string = STRING_ASSIGN!(value, length); if !(*emitter).whitespace && (length != 0 || (*emitter).flow_level != 0) && put(emitter, b' ').fail { return FAIL; } while string.pointer != string.end { if IS_SPACE!(string) { if allow_breaks && !spaces && (*emitter).column > (*emitter).best_width && !IS_SPACE_AT!(string, 1) { if yaml_emitter_write_indent(emitter).fail { return FAIL; } MOVE!(string); } else if write!(emitter, string).fail { return FAIL; } spaces = true; } else if IS_BREAK!(string) { if !breaks && CHECK!(string, b'\n') && put_break(emitter).fail { return FAIL; } if write_break!(emitter, string).fail { return FAIL; } (*emitter).indention = true; breaks = true; } else { if breaks && yaml_emitter_write_indent(emitter).fail { return FAIL; } if write!(emitter, string).fail { return FAIL; } (*emitter).indention = false; spaces = false; breaks = false; } } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_single_quoted_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, allow_breaks: bool, ) -> Success { let mut spaces = false; let mut breaks = false; let mut string = STRING_ASSIGN!(value, length); if yaml_emitter_write_indicator( emitter, b"'\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } while string.pointer != string.end { if IS_SPACE!(string) { if allow_breaks && !spaces && (*emitter).column > (*emitter).best_width && string.pointer != string.start && string.pointer != string.end.wrapping_offset(-1_isize) && !IS_SPACE_AT!(string, 1) { if yaml_emitter_write_indent(emitter).fail { return FAIL; } MOVE!(string); } else if write!(emitter, string).fail { return FAIL; } spaces = true; } else if IS_BREAK!(string) { if !breaks && CHECK!(string, b'\n') && put_break(emitter).fail { return FAIL; } if write_break!(emitter, string).fail { return FAIL; } (*emitter).indention = true; breaks = true; } else { if breaks && yaml_emitter_write_indent(emitter).fail { return FAIL; } if CHECK!(string, b'\'') && put(emitter, b'\'').fail { return FAIL; } if write!(emitter, string).fail { return FAIL; } (*emitter).indention = false; spaces = false; breaks = false; } } if breaks && yaml_emitter_write_indent(emitter).fail { return FAIL; } if yaml_emitter_write_indicator( emitter, b"'\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_double_quoted_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, allow_breaks: bool, ) -> Success { let mut spaces = false; let mut string = STRING_ASSIGN!(value, length); if yaml_emitter_write_indicator( emitter, b"\"\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } while string.pointer != string.end { if !IS_PRINTABLE!(string) || !(*emitter).unicode && !IS_ASCII!(string) || IS_BOM!(string) || IS_BREAK!(string) || CHECK!(string, b'"') || CHECK!(string, b'\\') { let mut octet: libc::c_uchar; let mut width: libc::c_uint; let mut value_0: libc::c_uint; let mut k: libc::c_int; octet = *string.pointer; width = if octet & 0x80 == 0x00 { 1 } else if octet & 0xE0 == 0xC0 { 2 } else if octet & 0xF0 == 0xE0 { 3 } else if octet & 0xF8 == 0xF0 { 4 } else { 0 }; value_0 = if octet & 0x80 == 0 { octet & 0x7F } else if octet & 0xE0 == 0xC0 { octet & 0x1F } else if octet & 0xF0 == 0xE0 { octet & 0x0F } else if octet & 0xF8 == 0xF0 { octet & 0x07 } else { 0 } as libc::c_uint; k = 1; while k < width as libc::c_int { octet = *string.pointer.wrapping_offset(k as isize); value_0 = (value_0 << 6) .force_add((octet & 0x3F) as libc::c_uint); k += 1; } string.pointer = string.pointer.wrapping_offset(width as isize); if put(emitter, b'\\').fail { return FAIL; } match value_0 { 0x00 => { if put(emitter, b'0').fail { return FAIL; } } 0x07 => { if put(emitter, b'a').fail { return FAIL; } } 0x08 => { if put(emitter, b'b').fail { return FAIL; } } 0x09 => { if put(emitter, b't').fail { return FAIL; } } 0x0A => { if put(emitter, b'n').fail { return FAIL; } } 0x0B => { if put(emitter, b'v').fail { return FAIL; } } 0x0C => { if put(emitter, b'f').fail { return FAIL; } } 0x0D => { if put(emitter, b'r').fail { return FAIL; } } 0x1B => { if put(emitter, b'e').fail { return FAIL; } } 0x22 => { if put(emitter, b'"').fail { return FAIL; } } 0x5C => { if put(emitter, b'\\').fail { return FAIL; } } 0x85 => { if put(emitter, b'N').fail { return FAIL; } } 0xA0 => { if put(emitter, b'_').fail { return FAIL; } } 0x2028 => { if put(emitter, b'L').fail { return FAIL; } } 0x2029 => { if put(emitter, b'P').fail { return FAIL; } } _ => { if value_0 <= 0xFF { if put(emitter, b'x').fail { return FAIL; } width = 2; } else if value_0 <= 0xFFFF { if put(emitter, b'u').fail { return FAIL; } width = 4; } else { if put(emitter, b'U').fail { return FAIL; } width = 8; } k = width.wrapping_sub(1).wrapping_mul(4) as libc::c_int; while k >= 0 { let digit: libc::c_int = (value_0 >> k & 0x0F) as libc::c_int; if put( emitter, (digit + if digit < 10 { b'0' } else { b'A' - 10 } as i32) as u8, ) .fail { return FAIL; } k -= 4; } } } spaces = false; } else if IS_SPACE!(string) { if allow_breaks && !spaces && (*emitter).column > (*emitter).best_width && string.pointer != string.start && string.pointer != string.end.wrapping_offset(-1_isize) { if yaml_emitter_write_indent(emitter).fail { return FAIL; } if IS_SPACE_AT!(string, 1) && put(emitter, b'\\').fail { return FAIL; } MOVE!(string); } else if write!(emitter, string).fail { return FAIL; } spaces = true; } else { if write!(emitter, string).fail { return FAIL; } spaces = false; } } if yaml_emitter_write_indicator( emitter, b"\"\0" as *const u8 as *const libc::c_char, false, false, false, ) .fail { return FAIL; } (*emitter).whitespace = false; (*emitter).indention = false; OK } unsafe fn yaml_emitter_write_block_scalar_hints( emitter: *mut YamlEmitterT, mut string: YamlStringT, ) -> Success { let mut indent_hint: [libc::c_char; 2] = [0; 2]; let mut chomp_hint: *const libc::c_char = ptr::null::(); if IS_SPACE!(string) || IS_BREAK!(string) { indent_hint[0] = (b'0' as libc::c_int + (*emitter).best_indent) as libc::c_char; indent_hint[1] = '\0' as libc::c_char; if yaml_emitter_write_indicator( emitter, indent_hint.as_mut_ptr(), false, false, false, ) .fail { return FAIL; } } (*emitter).open_ended = 0; string.pointer = string.end; if string.start == string.pointer { chomp_hint = b"-\0" as *const u8 as *const libc::c_char; } else { loop { string.pointer = string.pointer.wrapping_offset(-1); if *string.pointer & 0xC0 != 0x80 { break; } } if !IS_BREAK!(string) { chomp_hint = b"-\0" as *const u8 as *const libc::c_char; } else if string.start == string.pointer { chomp_hint = b"+\0" as *const u8 as *const libc::c_char; (*emitter).open_ended = 2; } else { loop { string.pointer = string.pointer.wrapping_offset(-1); if *string.pointer & 0xC0 != 0x80 { break; } } if IS_BREAK!(string) { chomp_hint = b"+\0" as *const u8 as *const libc::c_char; (*emitter).open_ended = 2; } } } if !chomp_hint.is_null() && yaml_emitter_write_indicator( emitter, chomp_hint, false, false, false, ) .fail { return FAIL; } OK } unsafe fn yaml_emitter_write_literal_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, ) -> Success { let mut breaks = true; let mut string = STRING_ASSIGN!(value, length); if yaml_emitter_write_indicator( emitter, b"|\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_block_scalar_hints(emitter, string).fail { return FAIL; } if put_break(emitter).fail { return FAIL; } (*emitter).indention = true; (*emitter).whitespace = true; while string.pointer != string.end { if IS_BREAK!(string) { if write_break!(emitter, string).fail { return FAIL; } (*emitter).indention = true; breaks = true; } else { if breaks && yaml_emitter_write_indent(emitter).fail { return FAIL; } if write!(emitter, string).fail { return FAIL; } (*emitter).indention = false; breaks = false; } } OK } unsafe fn yaml_emitter_write_folded_scalar( emitter: *mut YamlEmitterT, value: *mut yaml_char_t, length: size_t, ) -> Success { let mut breaks = true; let mut leading_spaces = true; let mut string = STRING_ASSIGN!(value, length); if yaml_emitter_write_indicator( emitter, b">\0" as *const u8 as *const libc::c_char, true, false, false, ) .fail { return FAIL; } if yaml_emitter_write_block_scalar_hints(emitter, string).fail { return FAIL; } if put_break(emitter).fail { return FAIL; } (*emitter).indention = true; (*emitter).whitespace = true; while string.pointer != string.end { if IS_BREAK!(string) { if !breaks && !leading_spaces && CHECK!(string, b'\n') { let mut k: libc::c_int = 0; while IS_BREAK_AT!(string, k as isize) { k += WIDTH_AT!(string, k as isize); } if !IS_BLANKZ_AT!(string, k as isize) && put_break(emitter).fail { return FAIL; } } if write_break!(emitter, string).fail { return FAIL; } (*emitter).indention = true; breaks = true; } else { if breaks { if yaml_emitter_write_indent(emitter).fail { return FAIL; } leading_spaces = IS_BLANK!(string); } if !breaks && IS_SPACE!(string) && !IS_SPACE_AT!(string, 1) && (*emitter).column > (*emitter).best_width { if yaml_emitter_write_indent(emitter).fail { return FAIL; } MOVE!(string); } else if write!(emitter, string).fail { return FAIL; } (*emitter).indention = false; breaks = false; } } OK } libyml-0.0.5/src/internal.rs000064400000000000000000000152461046102023000140770ustar 00000000000000use crate::{ externs::memmove, libc, memory::yaml_realloc, ops::{ForceAdd as _, ForceMul as _}, success::{Success, FAIL, OK}, yaml::{size_t, yaml_char_t}, PointerExt, }; /// Extend a stack by reallocating and copying the existing data. /// /// This function is used to grow a stack when more space is needed. /// /// # Safety /// /// - This function is unsafe because it directly calls the system's `realloc` function, /// which can lead to undefined behaviour if misused. /// - The caller must ensure that `start`, `top`, and `end` are valid pointers into the /// same allocated memory block. /// - The caller must ensure that the memory block being extended is large enough to /// accommodate the new size. /// - The caller is responsible for properly freeing the extended memory block using /// the corresponding `yaml_free` function when it is no longer needed. /// pub unsafe fn yaml_stack_extend( start: *mut *mut libc::c_void, top: *mut *mut libc::c_void, end: *mut *mut libc::c_void, ) { let new_start: *mut libc::c_void = yaml_realloc( *start, (((*end as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long) .force_mul(2_i64)) as size_t, ); *top = (new_start as *mut libc::c_char).wrapping_offset( (*top as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long as isize, ) as *mut libc::c_void; *end = (new_start as *mut libc::c_char).wrapping_offset( (((*end as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long) .force_mul(2_i64)) as isize, ) as *mut libc::c_void; *start = new_start; } /// Extend a queue by reallocating and copying the existing data. /// /// This function is used to grow a queue when more space is needed. /// /// # Safety /// /// - This function is unsafe because it directly calls the system's `realloc` and /// `memmove` functions, which can lead to undefined behaviour if misused. /// - The caller must ensure that `start`, `head`, `tail`, and `end` are valid pointers /// into the same allocated memory block. /// - The caller must ensure that the memory block being extended is large enough to /// accommodate the new size. /// - The caller is responsible for properly freeing the extended memory block using /// the corresponding `yaml_free` function when it is no longer needed. /// pub unsafe fn yaml_queue_extend( start: *mut *mut libc::c_void, head: *mut *mut libc::c_void, tail: *mut *mut libc::c_void, end: *mut *mut libc::c_void, ) { if *start == *head && *tail == *end { let new_start: *mut libc::c_void = yaml_realloc( *start, (((*end as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long) .force_mul(2_i64)) as size_t, ); *head = (new_start as *mut libc::c_char).wrapping_offset( (*head as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long as isize, ) as *mut libc::c_void; *tail = (new_start as *mut libc::c_char).wrapping_offset( (*tail as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long as isize, ) as *mut libc::c_void; *end = (new_start as *mut libc::c_char).wrapping_offset( (((*end as *mut libc::c_char) .c_offset_from(*start as *mut libc::c_char) as libc::c_long) .force_mul(2_i64)) as isize, ) as *mut libc::c_void; *start = new_start; } if *tail == *end { if *head != *tail { let _ = memmove( *start, *head, (*tail as *mut libc::c_char) .c_offset_from(*head as *mut libc::c_char) as libc::c_ulong, ); } *tail = (*start as *mut libc::c_char).wrapping_offset( (*tail as *mut libc::c_char) .c_offset_from(*head as *mut libc::c_char) as libc::c_long as isize, ) as *mut libc::c_void; *head = *start; } } /// Checks if the provided UTF-8 encoded string is valid according to the UTF-8 specification. /// /// # Parameters /// /// * `start`: A pointer to the start of the UTF-8 encoded string. /// * `length`: The length of the UTF-8 encoded string in bytes. /// /// # Return /// /// Returns `Success::OK` if the string is valid UTF-8, otherwise returns `Success::FAIL`. /// /// # Safety /// /// - `start` must be a valid, non-null pointer to a null-terminated UTF-8 string. /// - The UTF-8 encoded string must be properly formatted and not contain any invalid characters. /// - The string must be properly null-terminated. /// - The string must not contain any invalid characters or sequences. /// pub unsafe fn yaml_check_utf8( start: *const yaml_char_t, length: size_t, ) -> Success { let end: *const yaml_char_t = start.wrapping_offset(length as isize); let mut pointer: *const yaml_char_t = start; while pointer < end { let mut octet: libc::c_uchar; let mut value: libc::c_uint; let mut k: size_t; octet = *pointer; let width: libc::c_uint = if octet & 0x80 == 0 { 1 } else if octet & 0xE0 == 0xC0 { 2 } else if octet & 0xF0 == 0xE0 { 3 } else if octet & 0xF8 == 0xF0 { 4 } else { 0 } as libc::c_uint; value = if octet & 0x80 == 0 { octet & 0x7F } else if octet & 0xE0 == 0xC0 { octet & 0x1F } else if octet & 0xF0 == 0xE0 { octet & 0xF } else if octet & 0xF8 == 0xF0 { octet & 0x7 } else { 0 } as libc::c_uint; if width == 0 { return FAIL; } if pointer.wrapping_offset(width as isize) > end { return FAIL; } k = 1_u64; while k < width as libc::c_ulong { octet = *pointer.wrapping_offset(k as isize); if octet & 0xC0 != 0x80 { return FAIL; } value = (value << 6).force_add((octet & 0x3F) as libc::c_uint); k = k.force_add(1); } if !(width == 1 || width == 2 && value >= 0x80 || width == 3 && value >= 0x800 || width == 4 && value >= 0x10000) { return FAIL; } pointer = pointer.wrapping_offset(width as isize); } OK } libyml-0.0.5/src/lib.rs000064400000000000000000000435331046102023000130310ustar 00000000000000//! # LibYML (a fork of unsafe-libyaml) //! //! [![Made With Love][made-with-rust]][10] //! [![Crates.io][crates-badge]][06] //! [![lib.rs][libs-badge]][11] //! [![Docs.rs][docs-badge]][07] //! [![Codecov][codecov-badge]][08] //! [![Build Status][build-badge]][09] //! [![GitHub][github-badge]][05] //! //! LibYML is a Rust library for working with YAML data, forked from [unsafe-libyaml][01]. It offers a safe and efficient interface for parsing, emitting, and manipulating YAML data. //! //! ## Features //! //! - **Serialization and Deserialization**: Easy-to-use APIs for serializing Rust structs and enums to YAML and vice versa. //! - **Custom Struct and Enum Support**: Seamless serialization and deserialization of custom data types. //! - **Comprehensive Error Handling**: Detailed error messages and recovery mechanisms. //! - **Streaming Support**: Efficient processing of large YAML documents. //! - **Alias and Anchor Support**: Handling of complex YAML structures with references. //! - **Tag Handling**: Support for custom tags and type-specific serialization. //! - **Configurable Emitter**: Customizable YAML output generation. //! - **Extensive Documentation**: Detailed docs and examples for easy onboarding. //! - **Safety and Efficiency**: Minimized unsafe code with an interface designed to prevent common pitfalls. //! //! ## Installation //! //! Add this to your `Cargo.toml`: //! //! ```toml //! [dependencies] //! libyml = "0.0.5" //! ``` //! //! ## Documentation //! //! For full API documentation, please visit [https://doc.libyml.com/libyml/][03] or [https://docs.rs/libyml][07]. //! //! ## Rust Version Compatibility //! //! Compiler support: requires rustc 1.56.0+ //! //! ## Contributing //! //! Contributions are welcome! If you'd like to contribute, please feel free to submit a Pull Request on [GitHub][05]. //! //! ## Credits and Acknowledgements //! //! LibYML is a fork of the work done by [David Tolnay][04] and the maintainers of [unsafe-libyaml][01]. While it has evolved into a separate library, we express our sincere gratitude to them as well as the [libyaml][02] maintainers for their contributions to the Rust and C programming communities. //! //! ## License //! //! [MIT license](https://opensource.org/license/MIT), same as libyaml. //! //! [00]: https://libyml.com //! [01]: https://github.com/dtolnay/unsafe-libyaml //! [02]: https://github.com/yaml/libyaml/tree/2c891fc7a770e8ba2fec34fc6b545c672beb37e6 //! [03]: https://doc.libyml.com/libyml/ //! [04]: https://github.com/dtolnay //! [05]: https://github.com/sebastienrousseau/libyml //! [06]: https://crates.io/crates/libyml //! [07]: https://docs.rs/libyml //! [08]: https://codecov.io/gh/sebastienrousseau/libyml //! [09]: https://github.com/sebastienrousseau/libyml/actions?query=branch%3Amaster //! [10]: https://www.rust-lang.org/ //! [11]: https://lib.rs/crates/libyml //! //! [build-badge]: https://img.shields.io/github/actions/workflow/status/sebastienrousseau/libyml/release.yml?branch=master&style=for-the-badge&logo=github "Build Status" //! [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/libyml?style=for-the-badge&logo=codecov&token=yc9s578xIk "Code Coverage" //! [crates-badge]: https://img.shields.io/crates/v/libyml.svg?style=for-the-badge&color=fc8d62&logo=rust "View on Crates.io" //! [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.5-orange.svg?style=for-the-badge "View on lib.rs" //! [docs-badge]: https://img.shields.io/badge/docs.rs-libyml-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs "View Documentation" //! [github-badge]: https://img.shields.io/badge/github-sebastienrousseau/libyml-8da0cb?style=for-the-badge&labelColor=555555&logo=github "View on GitHub" //! [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' //! #![no_std] #![doc( html_favicon_url = "https://kura.pro/libyml/images/favicon.ico", html_logo_url = "https://kura.pro/libyml/images/logos/libyml.svg", html_root_url = "https://docs.rs/libyml" )] #![crate_name = "libyml"] #![crate_type = "lib"] extern crate alloc; use core::mem::size_of; /// Declarations for C library functions used within the LibYML library. /// /// This module contains the necessary types and constants required for /// interfacing with C libraries, particularly in the context of memory management /// and low-level operations within LibYML. pub mod libc { pub use core::ffi::c_void; pub use core::primitive::{ i32 as c_int, i64 as c_long, i8 as c_char, u32 as c_uint, u64 as c_ulong, u8 as c_uchar, }; } /// Extern functions and macros for interacting with the underlying libyaml C library. /// /// This module includes low-level functions for memory allocation, comparison, and /// movement that bridge Rust and C. It also contains some internal macros for /// asserting conditions in a way that integrates with the C code. #[macro_use] pub mod externs { use crate::libc; use crate::ops::{die, ForceAdd as _, ForceInto as _}; use alloc::alloc::{self as rust, Layout}; use core::mem::MaybeUninit; use core::mem::{align_of, size_of}; use core::ptr; use core::slice; const HEADER: usize = { let need_len = size_of::(); (need_len + MALLOC_ALIGN - 1) & !(MALLOC_ALIGN - 1) }; const MALLOC_ALIGN: usize = { let int_align = align_of::(); let ptr_align = align_of::(); if int_align >= ptr_align { int_align } else { ptr_align } }; /// Allocates memory. /// /// # Safety /// /// This function is unsafe because it directly manipulates raw memory. The caller must ensure that /// the allocated memory is properly managed and freed when no longer needed. pub unsafe fn malloc(size: libc::c_ulong) -> *mut libc::c_void { let size = HEADER.force_add(size.force_into()); let layout = Layout::from_size_align(size, MALLOC_ALIGN) .ok() .unwrap_or_else(die); let memory = rust::alloc(layout); if memory.is_null() { return die(); } memory.cast::().write(size); memory.add(HEADER).cast() } /// Reallocates memory. /// /// # Safety /// /// This function is unsafe because it directly manipulates raw memory. /// The caller must ensure that the original memory was allocated by `malloc`. pub(crate) unsafe fn realloc( ptr: *mut libc::c_void, new_size: libc::c_ulong, ) -> *mut libc::c_void { let mut memory = ptr.cast::().sub(HEADER); let size = memory.cast::().read(); let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN); let new_size = HEADER.force_add(new_size.force_into()); memory = rust::realloc(memory, layout, new_size); if memory.is_null() { return die(); } memory.cast::().write(new_size); memory.add(HEADER).cast() } /// Frees allocated memory. /// /// # Safety /// /// This function is unsafe because it deallocates memory pointed to by `ptr`. /// The caller must ensure that `ptr` was previously allocated by `malloc` or `realloc`. pub unsafe fn free(ptr: *mut libc::c_void) { let memory = ptr.cast::().sub(HEADER); let size = memory.cast::().read(); let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN); rust::dealloc(memory, layout); } /// Compares two memory blocks. /// /// # Safety /// /// This function is unsafe because it compares raw memory. The caller must ensure the pointers /// and size are correct. pub(crate) unsafe fn memcmp( lhs: *const libc::c_void, rhs: *const libc::c_void, count: libc::c_ulong, ) -> libc::c_int { let lhs = slice::from_raw_parts(lhs.cast::(), count as usize); let rhs = slice::from_raw_parts(rhs.cast::(), count as usize); lhs.cmp(rhs) as libc::c_int } /// Copies memory from `src` to `dest`. /// /// # Safety /// /// The caller must ensure that the memory areas do not overlap and that the destination is large /// enough to hold the data. pub(crate) unsafe fn memcpy( dest: *mut libc::c_void, src: *const libc::c_void, count: libc::c_ulong, ) -> *mut libc::c_void { if dest.is_null() || src.is_null() { return die(); } ptr::copy_nonoverlapping( src.cast::>(), dest.cast::>(), count as usize, ); dest } /// Moves memory from `src` to `dest`. /// /// # Safety /// /// The caller must ensure that the memory areas do not overlap or are correctly managed. pub unsafe fn memmove( dest: *mut libc::c_void, src: *const libc::c_void, count: libc::c_ulong, ) -> *mut libc::c_void { if dest.is_null() || src.is_null() { return die(); } ptr::copy( src.cast::>(), dest.cast::>(), count as usize, ); dest } /// Fills memory with a constant byte. /// /// # Safety /// /// The caller must ensure the memory is valid and the length is correct. pub unsafe fn memset( dest: *mut libc::c_void, ch: libc::c_int, count: libc::c_ulong, ) -> *mut libc::c_void { ptr::write_bytes(dest.cast::(), ch as u8, count as usize); dest } /// Compares two strings. /// /// # Safety /// /// The caller must ensure the strings are null-terminated and valid. pub(crate) unsafe fn strcmp( lhs: *const libc::c_char, rhs: *const libc::c_char, ) -> libc::c_int { if lhs.is_null() || rhs.is_null() { return die(); } let lhs = slice::from_raw_parts( lhs.cast::(), strlen(lhs) as usize, ); let rhs = slice::from_raw_parts( rhs.cast::(), strlen(rhs) as usize, ); lhs.cmp(rhs) as libc::c_int } /// Returns the length of a string. /// /// # Safety /// /// The caller must ensure the string is null-terminated and valid. pub(crate) unsafe fn strlen( str: *const libc::c_char, ) -> libc::c_ulong { let mut end = str; while *end != 0 { end = end.add(1); } end.offset_from(str) as libc::c_ulong } /// Compares up to `count` characters of two strings. /// /// # Safety /// /// The caller must ensure the strings are null-terminated and valid. pub(crate) unsafe fn strncmp( lhs: *const libc::c_char, rhs: *const libc::c_char, mut count: libc::c_ulong, ) -> libc::c_int { if lhs.is_null() || rhs.is_null() { return die(); } let mut lhs = lhs.cast::(); let mut rhs = rhs.cast::(); while count > 0 && *lhs != 0 && *lhs == *rhs { lhs = lhs.add(1); rhs = rhs.add(1); count -= 1; } if count == 0 { 0 } else { (*lhs).cmp(&*rhs) as libc::c_int } } /// Macro for asserting conditions. /// /// This macro is used internally to assert conditions and handle failures. macro_rules! __assert { (false $(,)?) => { $crate::externs::__assert_fail( stringify!(false), file!(), line!(), ) }; ($assertion:expr $(,)?) => { if !$assertion { $crate::externs::__assert_fail( stringify!($assertion), file!(), line!(), ); } }; } /// Internal function for handling assertion failures. /// /// # Safety /// /// This function is called when an assertion fails, and it triggers a panic. pub(crate) unsafe fn __assert_fail( __assertion: &'static str, __file: &'static str, __line: u32, ) -> ! { struct Abort; impl Drop for Abort { fn drop(&mut self) { panic!("arithmetic overflow"); } } let _abort_on_panic = Abort; panic!( "{}:{}: Assertion `{}` failed.", __file, __line, __assertion ); } } /// Module for formatting utilities. /// /// This module provides utilities for formatting data, /// particularly for writing formatted strings to pointers. mod fmt { use crate::yaml::yaml_char_t; use core::fmt::{self, Write}; use core::ptr; /// Struct for writing formatted data to a pointer. pub(crate) struct WriteToPtr { ptr: *mut yaml_char_t, } impl WriteToPtr { /// Creates a new `WriteToPtr`. /// /// # Safety /// /// This function is unsafe because it directly manipulates raw pointers. pub(crate) unsafe fn new(ptr: *mut yaml_char_t) -> Self { WriteToPtr { ptr } } /// Writes formatted data to the pointer. pub(crate) fn write_fmt(&mut self, args: fmt::Arguments<'_>) { let _ = Write::write_fmt(self, args); } } impl Write for WriteToPtr { fn write_str(&mut self, s: &str) -> fmt::Result { unsafe { ptr::copy_nonoverlapping(s.as_ptr(), self.ptr, s.len()); self.ptr = self.ptr.add(s.len()); } Ok(()) } } } /// Trait extension for pointers. /// /// This trait provides methods for working with pointers, /// particularly for calculating the offset between two pointers. trait PointerExt: Sized { fn c_offset_from(self, origin: Self) -> isize; } impl PointerExt for *const T { fn c_offset_from(self, origin: *const T) -> isize { (self as isize - origin as isize) / size_of::() as isize } } impl PointerExt for *mut T { fn c_offset_from(self, origin: *mut T) -> isize { (self as isize - origin as isize) / size_of::() as isize } } /// Macros module for LibYML. /// /// This module contains various macros used throughout the LibYML library. #[macro_use] pub mod macros; /// Utility functions for LibYML. /// /// This module contains utility functions and macros that are used throughout the LibYML library. #[macro_use] pub mod utils; /// API module for LibYML. /// /// This module provides the public API functions for working with YAML data. pub mod api; /// String utilities for LibYML. /// /// This module provides utilities for working with YAML strings. pub mod string; /// Dumper module for LibYML. /// /// This module contains functions related to dumping YAML data. pub mod dumper; /// Emitter module for LibYML. /// /// This module provides functions for emitting YAML data. mod emitter; /// Loader module for LibYML. /// /// This module contains functions for loading YAML data. pub mod loader; /// Decode module for LibYML. /// /// This module contains functions for decoding YAML data. pub mod decode; /// Document module for LibYML. /// /// This module provides functions for working with YAML documents. pub mod document; /// Internal utilities for LibYML. /// /// This module contains internal utility functions and structures for the library. pub mod internal; /// Memory management for LibYML. /// /// This module provides functions for managing memory within the library. pub mod memory; mod ops; mod parser; mod reader; mod scanner; /// Success and Failure types for LibYML. /// /// This module provides types for representing the success and failure of various operations within the library. pub mod success; mod writer; /// YAML API module for LibYML. /// /// This module provides functions and types for working directly with YAML data structures. pub mod yaml; pub use crate::api::{ yaml_alias_event_initialize, yaml_emitter_delete, yaml_emitter_initialize, yaml_emitter_set_break, yaml_emitter_set_canonical, yaml_emitter_set_encoding, yaml_emitter_set_indent, yaml_emitter_set_output, yaml_emitter_set_output_string, yaml_emitter_set_unicode, yaml_emitter_set_width, yaml_event_delete, yaml_mapping_end_event_initialize, yaml_mapping_start_event_initialize, yaml_parser_set_encoding, yaml_parser_set_input, yaml_parser_set_input_string, yaml_scalar_event_initialize, yaml_sequence_end_event_initialize, yaml_sequence_start_event_initialize, yaml_stream_end_event_initialize, yaml_stream_start_event_initialize, yaml_token_delete, }; pub use crate::decode::{yaml_parser_delete, yaml_parser_initialize}; pub use crate::document::{ yaml_document_delete, yaml_document_get_node, yaml_document_get_root_node, yaml_document_initialize, }; pub use crate::dumper::{ yaml_emitter_close, yaml_emitter_dump, yaml_emitter_open, }; pub use crate::emitter::yaml_emitter_emit; pub use crate::loader::yaml_parser_load; pub use crate::parser::yaml_parser_parse; pub use crate::scanner::yaml_parser_scan; pub use crate::writer::yaml_emitter_flush; pub use crate::yaml::{ YamlAliasDataT, YamlBreakT, YamlDocumentT, YamlEmitterStateT, YamlEmitterT, YamlEncodingT, YamlErrorTypeT, YamlEventT, YamlEventTypeT, YamlMappingStyleT, YamlMarkT, YamlNodeItemT, YamlNodePairT, YamlNodeT, YamlNodeTypeT, YamlParserStateT, YamlParserT, YamlReadHandlerT, YamlScalarStyleT, YamlSequenceStyleT, YamlSimpleKeyT, YamlStackT, YamlTagDirectiveT, YamlTokenT, YamlTokenTypeT, YamlVersionDirectiveT, YamlWriteHandlerT, }; #[doc(hidden)] pub use crate::yaml::{ YamlBreakT::*, YamlEmitterStateT::*, YamlEncodingT::*, YamlErrorTypeT::*, YamlEventTypeT::*, YamlMappingStyleT::*, YamlNodeTypeT::*, YamlParserStateT::*, YamlScalarStyleT::*, YamlSequenceStyleT::*, YamlTokenTypeT::*, }; libyml-0.0.5/src/loader.rs000064400000000000000000000541661046102023000135350ustar 00000000000000use crate::externs::{memset, strcmp}; use crate::internal::yaml_stack_extend; use crate::memory::{yaml_free, yaml_malloc, yaml_strdup}; use crate::success::{Success, FAIL, OK}; use crate::yaml::yaml_char_t; use crate::{ libc, yaml_document_delete, yaml_parser_parse, PointerExt, YamlAliasDataT, YamlAliasEvent, YamlComposerError, YamlDocumentEndEvent, YamlDocumentStartEvent, YamlDocumentT, YamlEventT, YamlMappingEndEvent, YamlMappingNode, YamlMappingStartEvent, YamlMarkT, YamlMemoryError, YamlNodeItemT, YamlNodePairT, YamlNodeT, YamlParserT, YamlScalarEvent, YamlScalarNode, YamlSequenceEndEvent, YamlSequenceNode, YamlSequenceStartEvent, YamlStreamEndEvent, YamlStreamStartEvent, }; use core::mem::{size_of, MaybeUninit}; use core::ptr::{self, addr_of_mut}; #[repr(C)] struct LoaderCtx { start: *mut libc::c_int, end: *mut libc::c_int, top: *mut libc::c_int, } /// Parse the input stream and produce the next YAML document. /// /// Call this function subsequently to produce a sequence of documents /// constituting the input stream. /// /// If the produced document has no root node, it means that the document end /// has been reached. /// /// An application is responsible for freeing any data associated with the /// produced document object using the yaml_document_delete() function. /// /// An application must not alternate the calls of yaml_parser_load() with the /// calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break /// the parser. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - `document` must be a valid, non-null pointer to a `YamlDocumentT` struct that can be safely written to. /// - The `YamlParserT` and `YamlDocumentT` structs must be properly aligned and have the expected memory layout. /// - The caller must call `yaml_document_delete` to free any data associated with the produced document object. /// - The caller must not alternate calls to `yaml_parser_load` with calls to `yaml_parser_scan` or `yaml_parser_parse` on the same `YamlParserT` instance. pub unsafe fn yaml_parser_load( parser: *mut YamlParserT, document: *mut YamlDocumentT, ) -> Success { let current_block: u64; let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); __assert!(!parser.is_null()); __assert!(!document.is_null()); let _ = memset( document as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); STACK_INIT!((*document).nodes, YamlNodeT); if !(*parser).stream_start_produced { if yaml_parser_parse(parser, event).fail { current_block = 6234624449317607669; } else { __assert!((*event).type_ == YamlStreamStartEvent); current_block = 7815301370352969686; } } else { current_block = 7815301370352969686; } if current_block != 6234624449317607669 { if (*parser).stream_end_produced { return OK; } if yaml_parser_parse(parser, event).ok { if (*event).type_ == YamlStreamEndEvent { return OK; } STACK_INIT!((*parser).aliases, YamlAliasDataT); let fresh6 = addr_of_mut!((*parser).document); *fresh6 = document; if yaml_parser_load_document(parser, event).ok { yaml_parser_delete_aliases(parser); let fresh7 = addr_of_mut!((*parser).document); *fresh7 = ptr::null_mut::(); return OK; } } } yaml_parser_delete_aliases(parser); yaml_document_delete(document); let fresh8 = addr_of_mut!((*parser).document); *fresh8 = ptr::null_mut::(); FAIL } /// Sets the error type to `YamlComposerError` and stores the problem and its mark. /// /// # Parameters /// /// * `parser`: A mutable pointer to the `YamlParserT` struct. /// * `problem`: A pointer to a constant C string representing the problem. /// * `problem_mark`: A `YamlMarkT` struct representing the mark where the problem occurred. /// /// # Return /// /// Returns `FAIL` to indicate an error. /// /// # Safety /// /// - `parser` must be a valid, non-null pointer to a properly initialized `YamlParserT` struct. /// - `problem` must be a valid, non-null pointer to a constant C string. /// - `problem_mark` must be a valid `YamlMarkT` struct. /// - The `YamlParserT` struct must be properly aligned and have the expected memory layout. /// - The `problem` string must be null-terminated. /// - The `problem_mark` struct must be properly initialized. /// - The caller must handle the error and clean up any resources. /// pub unsafe fn yaml_parser_set_composer_error( parser: *mut YamlParserT, problem: *const libc::c_char, problem_mark: YamlMarkT, ) -> Success { (*parser).error = YamlComposerError; let fresh9 = addr_of_mut!((*parser).problem); *fresh9 = problem; (*parser).problem_mark = problem_mark; FAIL } unsafe fn yaml_parser_set_composer_error_context( parser: *mut YamlParserT, context: *const libc::c_char, context_mark: YamlMarkT, problem: *const libc::c_char, problem_mark: YamlMarkT, ) -> Success { (*parser).error = YamlComposerError; let fresh10 = addr_of_mut!((*parser).context); *fresh10 = context; (*parser).context_mark = context_mark; let fresh11 = addr_of_mut!((*parser).problem); *fresh11 = problem; (*parser).problem_mark = problem_mark; FAIL } unsafe fn yaml_parser_delete_aliases(parser: *mut YamlParserT) { while !STACK_EMPTY!((*parser).aliases) { yaml_free(POP!((*parser).aliases).anchor as *mut libc::c_void); } STACK_DEL!((*parser).aliases); } unsafe fn yaml_parser_load_document( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let mut ctx = LoaderCtx { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; __assert!((*event).type_ == YamlDocumentStartEvent); let fresh16 = addr_of_mut!((*(*parser).document).version_directive); *fresh16 = (*event).data.document_start.version_directive; let fresh17 = addr_of_mut!((*(*parser).document).tag_directives.start); *fresh17 = (*event).data.document_start.tag_directives.start; let fresh18 = addr_of_mut!((*(*parser).document).tag_directives.end); *fresh18 = (*event).data.document_start.tag_directives.end; (*(*parser).document).start_implicit = (*event).data.document_start.implicit; (*(*parser).document).start_mark = (*event).start_mark; STACK_INIT!(ctx, libc::c_int); if yaml_parser_load_nodes(parser, addr_of_mut!(ctx)).fail { STACK_DEL!(ctx); return FAIL; } STACK_DEL!(ctx); OK } unsafe fn yaml_parser_load_nodes( parser: *mut YamlParserT, ctx: *mut LoaderCtx, ) -> Success { let mut event = MaybeUninit::::uninit(); let event = event.as_mut_ptr(); loop { if yaml_parser_parse(parser, event).fail { return FAIL; } match (*event).type_ { YamlAliasEvent => { if yaml_parser_load_alias(parser, event, ctx).fail { return FAIL; } } YamlScalarEvent => { if yaml_parser_load_scalar(parser, event, ctx).fail { return FAIL; } } YamlSequenceStartEvent => { if yaml_parser_load_sequence(parser, event, ctx).fail { return FAIL; } } YamlSequenceEndEvent => { if yaml_parser_load_sequence_end(parser, event, ctx) .fail { return FAIL; } } YamlMappingStartEvent => { if yaml_parser_load_mapping(parser, event, ctx).fail { return FAIL; } } YamlMappingEndEvent => { if yaml_parser_load_mapping_end(parser, event, ctx).fail { return FAIL; } } YamlDocumentEndEvent => {} _ => { __assert!(false); } } if (*event).type_ == YamlDocumentEndEvent { break; } } (*(*parser).document).end_implicit = (*event).data.document_end.implicit; (*(*parser).document).end_mark = (*event).end_mark; OK } unsafe fn yaml_parser_register_anchor( parser: *mut YamlParserT, index: libc::c_int, anchor: *mut yaml_char_t, ) -> Success { let mut data = MaybeUninit::::uninit(); let data = data.as_mut_ptr(); let mut alias_data: *mut YamlAliasDataT; if anchor.is_null() { return OK; } (*data).anchor = anchor; (*data).index = index; (*data).mark = (*(*(*parser).document) .nodes .start .wrapping_offset((index - 1) as isize)) .start_mark; alias_data = (*parser).aliases.start; while alias_data != (*parser).aliases.top { if strcmp( (*alias_data).anchor as *mut libc::c_char, anchor as *mut libc::c_char, ) == 0 { yaml_free(anchor as *mut libc::c_void); return yaml_parser_set_composer_error_context( parser, b"found duplicate anchor; first occurrence\0" as *const u8 as *const libc::c_char, (*alias_data).mark, b"second occurrence\0" as *const u8 as *const libc::c_char, (*data).mark, ); } alias_data = alias_data.wrapping_offset(1); } PUSH!((*parser).aliases, *data); OK } unsafe fn yaml_parser_load_node_add( parser: *mut YamlParserT, ctx: *mut LoaderCtx, index: libc::c_int, ) -> Success { if STACK_EMPTY!(*ctx) { return OK; } let parent_index: libc::c_int = *(*ctx).top.wrapping_offset(-1_isize); let parent: *mut YamlNodeT = addr_of_mut!(*((*(*parser).document).nodes.start) .wrapping_offset((parent_index - 1) as isize)); let current_block_17: u64; match (*parent).type_ { YamlSequenceNode => { if STACK_LIMIT!(parser, (*parent).data.sequence.items).fail { return FAIL; } PUSH!((*parent).data.sequence.items, index); } YamlMappingNode => { let mut pair = MaybeUninit::::uninit(); let pair = pair.as_mut_ptr(); if !STACK_EMPTY!((*parent).data.mapping.pairs) { let p: *mut YamlNodePairT = (*parent) .data .mapping .pairs .top .wrapping_offset(-1_isize); if (*p).key != 0 && (*p).value == 0 { (*p).value = index; current_block_17 = 11307063007268554308; } else { current_block_17 = 17407779659766490442; } } else { current_block_17 = 17407779659766490442; } match current_block_17 { 11307063007268554308 => {} _ => { (*pair).key = index; (*pair).value = 0; if STACK_LIMIT!( parser, (*parent).data.mapping.pairs ) .fail { return FAIL; } PUSH!((*parent).data.mapping.pairs, *pair); } } } _ => { __assert!(false); } } OK } unsafe fn yaml_parser_load_alias( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { let anchor: *mut yaml_char_t = (*event).data.alias.anchor; let mut alias_data: *mut YamlAliasDataT; alias_data = (*parser).aliases.start; while alias_data != (*parser).aliases.top { if strcmp( (*alias_data).anchor as *mut libc::c_char, anchor as *mut libc::c_char, ) == 0 { yaml_free(anchor as *mut libc::c_void); return yaml_parser_load_node_add( parser, ctx, (*alias_data).index, ); } alias_data = alias_data.wrapping_offset(1); } yaml_free(anchor as *mut libc::c_void); yaml_parser_set_composer_error( parser, b"found undefined alias\0" as *const u8 as *const libc::c_char, (*event).start_mark, ) } unsafe fn yaml_parser_load_scalar( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { let current_block: u64; let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); let index: libc::c_int; let mut tag: *mut yaml_char_t = (*event).data.scalar.tag; if STACK_LIMIT!(parser, (*(*parser).document).nodes).ok { if tag.is_null() || strcmp( tag as *mut libc::c_char, b"!\0" as *const u8 as *const libc::c_char, ) == 0 { yaml_free(tag as *mut libc::c_void); tag = yaml_strdup( b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, ); if tag.is_null() { current_block = 10579931339944277179; } else { current_block = 11006700562992250127; } } else { current_block = 11006700562992250127; } if current_block != 10579931339944277179 { let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlScalarNode; (*node).tag = tag; (*node).start_mark = (*event).start_mark; (*node).end_mark = (*event).end_mark; (*node).data.scalar.value = (*event).data.scalar.value; (*node).data.scalar.length = (*event).data.scalar.length; (*node).data.scalar.style = (*event).data.scalar.style; PUSH!((*(*parser).document).nodes, *node); index = (*(*parser).document) .nodes .top .c_offset_from((*(*parser).document).nodes.start) as libc::c_int; if yaml_parser_register_anchor( parser, index, (*event).data.scalar.anchor, ) .fail { return FAIL; } return yaml_parser_load_node_add(parser, ctx, index); } } yaml_free(tag as *mut libc::c_void); yaml_free((*event).data.scalar.anchor as *mut libc::c_void); yaml_free((*event).data.scalar.value as *mut libc::c_void); FAIL } unsafe fn yaml_parser_load_sequence( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { let current_block: u64; let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); struct Items { start: *mut YamlNodeItemT, end: *mut YamlNodeItemT, top: *mut YamlNodeItemT, } let mut items = Items { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let index: libc::c_int; let mut tag: *mut yaml_char_t = (*event).data.sequence_start.tag; if STACK_LIMIT!(parser, (*(*parser).document).nodes).ok { if tag.is_null() || strcmp( tag as *mut libc::c_char, b"!\0" as *const u8 as *const libc::c_char, ) == 0 { yaml_free(tag as *mut libc::c_void); tag = yaml_strdup( b"tag:yaml.org,2002:seq\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, ); if tag.is_null() { current_block = 13474536459355229096; } else { current_block = 6937071982253665452; } } else { current_block = 6937071982253665452; } if current_block != 13474536459355229096 { STACK_INIT!(items, YamlNodeItemT); let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlSequenceNode; (*node).tag = tag; (*node).start_mark = (*event).start_mark; (*node).end_mark = (*event).end_mark; (*node).data.sequence.items.start = items.start; (*node).data.sequence.items.end = items.end; (*node).data.sequence.items.top = items.start; (*node).data.sequence.style = (*event).data.sequence_start.style; PUSH!((*(*parser).document).nodes, *node); index = (*(*parser).document) .nodes .top .c_offset_from((*(*parser).document).nodes.start) as libc::c_int; if yaml_parser_register_anchor( parser, index, (*event).data.sequence_start.anchor, ) .fail { return FAIL; } if yaml_parser_load_node_add(parser, ctx, index).fail { return FAIL; } if STACK_LIMIT!(parser, *ctx).fail { return FAIL; } PUSH!(*ctx, index); return OK; } } yaml_free(tag as *mut libc::c_void); yaml_free((*event).data.sequence_start.anchor as *mut libc::c_void); FAIL } unsafe fn yaml_parser_load_sequence_end( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { __assert!( ((*ctx).top).c_offset_from((*ctx).start) as libc::c_long > 0_i64 ); let index: libc::c_int = *(*ctx).top.wrapping_offset(-1_isize); __assert!( (*((*(*parser).document).nodes.start) .wrapping_offset((index - 1) as isize)) .type_ == YamlSequenceNode ); (*(*(*parser).document) .nodes .start .wrapping_offset((index - 1) as isize)) .end_mark = (*event).end_mark; let _ = POP!(*ctx); OK } unsafe fn yaml_parser_load_mapping( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { let current_block: u64; let mut node = MaybeUninit::::uninit(); let node = node.as_mut_ptr(); struct Pairs { start: *mut YamlNodePairT, end: *mut YamlNodePairT, top: *mut YamlNodePairT, } let mut pairs = Pairs { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let index: libc::c_int; let mut tag: *mut yaml_char_t = (*event).data.mapping_start.tag; if STACK_LIMIT!(parser, (*(*parser).document).nodes).ok { if tag.is_null() || strcmp( tag as *mut libc::c_char, b"!\0" as *const u8 as *const libc::c_char, ) == 0 { yaml_free(tag as *mut libc::c_void); tag = yaml_strdup( b"tag:yaml.org,2002:map\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, ); if tag.is_null() { current_block = 13635467803606088781; } else { current_block = 6937071982253665452; } } else { current_block = 6937071982253665452; } if current_block != 13635467803606088781 { STACK_INIT!(pairs, YamlNodePairT); let _ = memset( node as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*node).type_ = YamlMappingNode; (*node).tag = tag; (*node).start_mark = (*event).start_mark; (*node).end_mark = (*event).end_mark; (*node).data.mapping.pairs.start = pairs.start; (*node).data.mapping.pairs.end = pairs.end; (*node).data.mapping.pairs.top = pairs.start; (*node).data.mapping.style = (*event).data.mapping_start.style; PUSH!((*(*parser).document).nodes, *node); index = (*(*parser).document) .nodes .top .c_offset_from((*(*parser).document).nodes.start) as libc::c_int; if yaml_parser_register_anchor( parser, index, (*event).data.mapping_start.anchor, ) .fail { return FAIL; } if yaml_parser_load_node_add(parser, ctx, index).fail { return FAIL; } if STACK_LIMIT!(parser, *ctx).fail { return FAIL; } PUSH!(*ctx, index); return OK; } } yaml_free(tag as *mut libc::c_void); yaml_free((*event).data.mapping_start.anchor as *mut libc::c_void); FAIL } unsafe fn yaml_parser_load_mapping_end( parser: *mut YamlParserT, event: *mut YamlEventT, ctx: *mut LoaderCtx, ) -> Success { __assert!( ((*ctx).top).c_offset_from((*ctx).start) as libc::c_long > 0_i64 ); let index: libc::c_int = *(*ctx).top.wrapping_offset(-1_isize); __assert!( (*((*(*parser).document).nodes.start) .wrapping_offset((index - 1) as isize)) .type_ == YamlMappingNode ); (*(*(*parser).document) .nodes .start .wrapping_offset((index - 1) as isize)) .end_mark = (*event).end_mark; let _ = POP!(*ctx); OK } libyml-0.0.5/src/macros.rs000064400000000000000000001136161046102023000135470ustar 00000000000000// ------------------------------------ // Buffer Management Macros // ------------------------------------ /// Initializes a buffer with a given size. /// /// # Parameters /// /// * `buffer`: A mutable reference to a `YamlBufferT` struct that needs to be initialized. /// * `size`: The size of the buffer in bytes. /// /// # Return /// /// This macro does not return a value. It initializes the provided buffer with the given size. /// /// # Safety /// /// This macro assumes that the `yaml_malloc` function is correctly implemented and handles memory allocation. #[macro_export] macro_rules! BUFFER_INIT { ($buffer:expr, $size:expr) => {{ let start = addr_of_mut!($buffer.start); *start = yaml_malloc($size as size_t) as *mut yaml_char_t; let pointer = addr_of_mut!($buffer.pointer); *pointer = $buffer.start; let last = addr_of_mut!($buffer.last); *last = *pointer; let end = addr_of_mut!($buffer.end); *end = $buffer.start.wrapping_add($size); }}; } /// Deletes the buffer and frees the allocated memory. /// /// # Parameters /// /// * `buffer`: A mutable reference to the buffer to be deleted. /// /// # Return /// /// This function does not return a value. #[macro_export] macro_rules! BUFFER_DEL { ($buffer:expr) => {{ // Free the allocated memory yaml_free($buffer.start as *mut libc::c_void); // Set all pointers to null after freeing the memory $buffer.start = ptr::null_mut::(); $buffer.pointer = ptr::null_mut::(); $buffer.last = ptr::null_mut::(); $buffer.end = ptr::null_mut::(); }}; } // ------------------------------------ // String Management Macros // ------------------------------------ /// Assigns a new value to a `YamlStringT` struct. /// /// This macro creates a new `YamlStringT` instance with the given start and end pointers. /// The end pointer is calculated by offsetting the start pointer by the given length. /// The pointer is set to the start pointer. /// /// # Parameters /// /// * `string`: A pointer to the start of the string. /// * `length`: The length of the string. /// /// # Return /// /// A new `YamlStringT` instance with the given start, end, and pointer values. #[macro_export] macro_rules! STRING_ASSIGN { ($string:expr, $length:expr) => { YamlStringT { start: $string, end: $string.wrapping_offset($length as isize), pointer: $string, } }; } /// Initializes a string for use with the yaml library. /// /// This macro allocates memory for a string, initializes the start, pointer, and end pointers, /// and sets the memory to all zeros. /// /// # Parameters /// /// * `$string`: A mutable reference to a `YamlStringT` struct, representing the string to be initialized. /// /// # Return /// /// This macro does not return a value. #[macro_export] macro_rules! STRING_INIT { ($string:expr) => {{ $string.start = yaml_malloc(16) as *mut yaml_char_t; $string.pointer = $string.start; $string.end = $string.start.wrapping_add(16); let _ = memset($string.start as *mut libc::c_void, 0, 16); }}; } /// Deletes a string and frees the allocated memory. /// /// # Parameters /// /// * `string`: A mutable reference to a `YamlStringT` struct representing the string to be deleted. /// /// # Return /// /// This function does not return a value. /// /// # Safety /// /// This function assumes that the `string` parameter is a valid pointer to a `YamlStringT` struct. /// It calls the `yaml_free` function to free the allocated memory for the string. #[macro_export] macro_rules! STRING_DEL { ($string:expr) => {{ yaml_free($string.start as *mut libc::c_void); $string.end = ptr::null_mut::(); $string.pointer = $string.end; $string.start = $string.pointer; }}; } /// Extends the capacity of a string by reallocating memory if the current capacity is insufficient. /// /// # Parameters /// /// * `string`: A mutable reference to a `YamlStringT` struct representing the string. /// /// # Return /// /// This macro does not return a value. It extends the capacity of the string by reallocating memory if necessary. #[macro_export] macro_rules! STRING_EXTEND { ($string:expr) => { if $string.pointer.wrapping_add(5) >= $string.end { yaml_string_extend( addr_of_mut!($string.start), addr_of_mut!($string.pointer), addr_of_mut!($string.end), ); } }; } /// Clears the content of the string by setting the pointer to the start and filling the memory /// from the start to the end with zeros. /// /// # Parameters /// /// * `string`: A mutable reference to a struct containing the start, pointer, and end pointers representing the string. /// /// # Return /// /// This macro does not return a value. It modifies the content of the string in place. #[macro_export] macro_rules! CLEAR { ($string:expr) => {{ $string.pointer = $string.start; let _ = memset( $string.start as *mut libc::c_void, 0, $string.end.offset_from($string.start) as libc::c_ulong, ); }}; } /// Joins two strings together by appending the contents of `string_b` to `string_a`. /// /// # Parameters /// /// * `string_a`: A mutable reference to the first string. Its contents will be modified. /// * `string_b`: A mutable reference to the second string. Its contents will not be modified. /// /// # Return /// /// This macro does not return a value. It modifies the contents of `string_a` in-place. #[macro_export] macro_rules! JOIN { ($string_a:expr, $string_b:expr) => {{ // Check the length to ensure we don't overflow let a_len = $string_a.pointer.offset_from($string_a.start) as usize; let b_len = $string_b.pointer.offset_from($string_b.start) as usize; // If the combined length would exceed available space, reallocate if a_len.checked_add(b_len).is_some() && $string_a.pointer.add(b_len) <= $string_a.end { yaml_string_join( addr_of_mut!($string_a.start), addr_of_mut!($string_a.pointer), addr_of_mut!($string_a.end), addr_of_mut!($string_b.start), addr_of_mut!($string_b.pointer), addr_of_mut!($string_b.end), ); $string_b.pointer = $string_b.start; } else { panic!("String join would overflow memory bounds"); } }}; } /// This macro checks if the octet at the specified offset in the given string matches the provided octet. /// /// # Parameters /// /// * `string`: A reference to the string where the octet will be checked. /// * `octet`: The octet to be checked. /// * `offset`: The offset from the start of the string where the octet will be checked. /// /// # Return /// /// * `bool`: Returns `true` if the octet at the specified offset matches the provided octet, otherwise returns `false`. #[macro_export] macro_rules! CHECK_AT { ($string:expr, $octet:expr, $offset:expr) => { *$string.pointer.offset($offset) == $octet }; } /// A macro that checks if the current byte in the given string matches a specific octet. /// /// # Parameters /// /// * `string`: A reference to the string to be checked. /// * `octet`: The octet to be matched. /// /// # Return /// /// * `bool`: Returns `true` if the current byte in the string matches the given octet, otherwise `false`. #[macro_export] macro_rules! CHECK { ($string:expr, $octet:expr) => { *$string.pointer == $octet }; } /// Checks if the current character in the string is an alphabetic character. /// /// # Parameters /// /// * `string`: A mutable reference to a struct containing a pointer to a byte array. /// /// # Return /// /// Returns `true` if the current character is an alphabetic character (A-Z, a-z, 0-9, '_', '-'), /// and `false` otherwise. #[macro_export] macro_rules! IS_ALPHA { ($string:expr) => { *$string.pointer >= b'0' && *$string.pointer <= b'9' || *$string.pointer >= b'A' && *$string.pointer <= b'Z' || *$string.pointer >= b'a' && *$string.pointer <= b'z' || *$string.pointer == b'_' || *$string.pointer == b'-' }; } /// Checks if the byte pointed to by the `pointer` in the given string is a digit (0-9). /// /// # Parameters /// /// * `string`: A reference to a struct containing a `pointer` field pointing to a byte in a string. /// /// # Return value /// /// Returns `true` if the byte pointed to by the `pointer` is a digit (0-9), and `false` otherwise. #[macro_export] macro_rules! IS_DIGIT { ($string:expr) => { *$string.pointer >= b'0' && *$string.pointer <= b'9' }; } /// Converts the byte at the current pointer in the string to its corresponding integer value. /// /// # Parameters /// /// * `string`: A mutable reference to a struct containing a pointer to a byte array. /// /// # Return /// /// * Returns the integer value of the byte at the current pointer in the string. /// The byte is assumed to be in the ASCII range (0-9), so the function subtracts the ASCII value of '0' (48) /// to convert it to its integer representation. #[macro_export] macro_rules! AS_DIGIT { ($string:expr) => { (*$string.pointer - b'0') as libc::c_int }; } /// Checks if the character at the given offset in the string is a hexadecimal digit. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// * `offset`: The offset in the string to check. /// /// # Return /// /// Returns `true` if the character at the given offset is a hexadecimal digit (0-9, A-F, a-f), /// and `false` otherwise. #[macro_export] macro_rules! IS_HEX_AT { ($string:expr, $offset:expr) => { *$string.pointer.wrapping_offset($offset) >= b'0' && *$string.pointer.wrapping_offset($offset) <= b'9' || *$string.pointer.wrapping_offset($offset) >= b'A' && *$string.pointer.wrapping_offset($offset) <= b'F' || *$string.pointer.wrapping_offset($offset) >= b'a' && *$string.pointer.wrapping_offset($offset) <= b'f' }; } /// Converts a hexadecimal character at a given offset in a string to its corresponding integer value. /// /// # Parameters /// /// * `string`: A reference to a string containing hexadecimal characters. /// * `offset`: The offset in the string where the hexadecimal character is located. /// /// # Return /// /// An integer representing the hexadecimal value of the character at the given offset. /// /// # Note /// /// This macro assumes that the input string contains valid hexadecimal characters. #[macro_export] macro_rules! AS_HEX_AT { ($string:expr, $offset:expr) => { if *$string.pointer.wrapping_offset($offset) >= b'A' && *$string.pointer.wrapping_offset($offset) <= b'F' { *$string.pointer.wrapping_offset($offset) - b'A' + 10 } else if *$string.pointer.wrapping_offset($offset) >= b'a' && *$string.pointer.wrapping_offset($offset) <= b'f' { *$string.pointer.wrapping_offset($offset) - b'a' + 10 } else { *$string.pointer.wrapping_offset($offset) - b'0' } as libc::c_int }; } /// Checks if the current character in the string is an ASCII character. /// /// # Parameters /// /// * `string`: A reference to a struct containing a pointer to the current character in the string. /// /// # Return /// /// Returns `true` if the current character is an ASCII character (i.e., its value is less than or equal to 0x7F), /// and `false` otherwise. #[macro_export] macro_rules! IS_ASCII { ($string:expr) => { *$string.pointer <= b'\x7F' }; } /// Checks if the character at the current pointer in the given string is printable. /// /// # Parameters /// /// * `string`: A reference to a struct containing a pointer to the current character in the string. /// /// # Return /// /// * `bool`: Returns `true` if the character is printable, and `false` otherwise. /// /// # Details /// /// This macro checks if the character at the current pointer in the given string is printable. /// It considers various Unicode ranges and special characters to determine printability. /// /// The macro uses pattern matching to check the byte value of the character and its position in the string. /// It checks for ASCII printable characters, Unicode printable characters in specific ranges, /// and special characters that are considered printable. /// /// The macro returns `true` if the character is printable, and `false` otherwise. #[macro_export] macro_rules! IS_PRINTABLE { ($string:expr) => { match *$string.pointer { // ASCII 0x0A | 0x20..=0x7E => true, // U+A0 ... U+BF 0xC2 => match *$string.pointer.wrapping_offset(1) { 0xA0..=0xBF => true, _ => false, }, // U+C0 ... U+CFFF 0xC3..=0xEC => true, // U+D000 ... U+D7FF 0xED => match *$string.pointer.wrapping_offset(1) { 0x00..=0x9F => true, _ => false, }, // U+E000 ... U+EFFF 0xEE => true, // U+F000 ... U+FFFD 0xEF => match *$string.pointer.wrapping_offset(1) { 0xBB => match *$string.pointer.wrapping_offset(2) { // except U+FEFF 0xBF => false, _ => true, }, 0xBF => match *$string.pointer.wrapping_offset(2) { 0xBE | 0xBF => false, _ => true, }, _ => true, }, // U+10000 ... U+10FFFF 0xF0..=0xF4 => true, _ => false, } }; } /// Checks if the character at the specified offset in the given string is a null character (ASCII 0). /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// Returns `true` if the character at the specified offset is a null character, and `false` otherwise. #[macro_export] macro_rules! IS_Z_AT { ($string:expr, $offset:expr) => { CHECK_AT!($string, b'\0', $offset) }; } /// Checks if the character at the current pointer in the given string is a null character (ASCII 0). /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character is a null character, and `false` otherwise. #[macro_export] macro_rules! IS_Z { ($string:expr) => { IS_Z_AT!($string, 0) }; } /// Checks if the first three bytes of the given string form the UTF-8 byte order mark (BOM) for UTF-8 encoding. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the first three bytes of the string form the UTF-8 BOM, and `false` otherwise. #[macro_export] macro_rules! IS_BOM { ($string:expr) => { CHECK_AT!($string, b'\xEF', 0) && CHECK_AT!($string, b'\xBB', 1) && CHECK_AT!($string, b'\xBF', 2) }; } /// Checks if the character at the specified offset in the given string is a space character (ASCII 0x20). /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character at the specified offset is a space character, and `false` otherwise. #[macro_export] macro_rules! IS_SPACE_AT { ($string:expr, $offset:expr) => { CHECK_AT!($string, b' ', $offset) }; } /// Checks if the character at the current pointer in the given string is a space character (ASCII 0x20). /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character is a space character, and `false` otherwise. #[macro_export] macro_rules! IS_SPACE { ($string:expr) => { IS_SPACE_AT!($string, 0) }; } /// Checks if the character at the specified offset in the given string is a tab character (ASCII 0x09). /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character at the specified offset is a tab character, and `false` otherwise. #[macro_export] macro_rules! IS_TAB_AT { ($string:expr, $offset:expr) => { CHECK_AT!($string, b'\t', $offset) }; } /// Checks if the character at the current pointer in the given string is a tab character (ASCII 0x09). /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character is a tab character, and `false` otherwise. #[macro_export] macro_rules! IS_TAB { ($string:expr) => { IS_TAB_AT!($string, 0) }; } /// Checks if the character at the specified offset in the given string is a space or tab character. /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character at the specified offset is a space or tab character, and `false` otherwise. #[macro_export] macro_rules! IS_BLANK_AT { ($string:expr, $offset:expr) => { IS_SPACE_AT!($string, $offset) || IS_TAB_AT!($string, $offset) }; } /// Checks if the character at the current pointer in the given string is a space or tab character. /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// /// # Return /// /// * `bool`: Returns `true` if the character is a space or tab character, and `false` otherwise. #[macro_export] macro_rules! IS_BLANK { ($string:expr) => { IS_BLANK_AT!($string, 0) }; } /// Checks if the character at the specified offset in the given string is a line break character. /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// Returns `true` if the character at the specified offset is a line break character (CR, LF, NEL, LS, PS), /// and `false` otherwise. #[macro_export] macro_rules! IS_BREAK_AT { ($string:expr, $offset:expr) => { CHECK_AT!($string, b'\r', $offset) || CHECK_AT!($string, b'\n', $offset) || CHECK_AT!($string, b'\xC2', $offset) && CHECK_AT!( $string, b'\x85', ($offset + 1).try_into().unwrap() ) || CHECK_AT!($string, b'\xE2', $offset) && CHECK_AT!( $string, b'\x80', ($offset + 1).try_into().unwrap() ) && CHECK_AT!( $string, b'\xA8', ($offset + 2).try_into().unwrap() ) || CHECK_AT!($string, b'\xE2', $offset) && CHECK_AT!( $string, b'\x80', ($offset + 1).try_into().unwrap() ) && CHECK_AT!( $string, b'\xA9', ($offset + 2).try_into().unwrap() ) }; } /// Checks if the character at the current pointer in the given string is a line break character. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// Returns `true` if the character is a line break character (CR, LF, NEL, LS, PS), and `false` otherwise. #[macro_export] macro_rules! IS_BREAK { ($string:expr) => { IS_BREAK_AT!($string, 0) }; } /// Checks if the character at the current pointer in the given string is a carriage return followed by a line feed. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// Returns `true` if the character at the current pointer is a carriage return followed by a line feed, and `false` otherwise. #[macro_export] macro_rules! IS_CRLF { ($string:expr) => { CHECK_AT!($string, b'\r', 0) && CHECK_AT!($string, b'\n', 1) }; } /// Checks if the character at the specified offset in the given string is a line break character or a null character. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// * `offset`: The offset within the string to check. /// /// # Return /// /// Returns `true` if the character at the specified offset is a line break character or a null character, and `false` otherwise. #[macro_export] macro_rules! IS_BREAKZ_AT { ($string:expr, $offset:expr) => { IS_BREAK_AT!($string, $offset) || IS_Z_AT!($string, $offset) }; } /// Checks if the character at the current pointer in the given string is a line break character or a null character. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// Returns `true` if the character is a line break character (CR, LF, NEL, LS, PS) or a null character, and `false` otherwise. #[macro_export] macro_rules! IS_BREAKZ { ($string:expr) => { IS_BREAKZ_AT!($string, 0) }; } /// Checks if the character at the specified offset in the given string is a space, tab, or line break character, /// or if it is a null character. /// /// # Parameters /// /// * `$string`: A reference to the string to check. /// * `$offset`: The offset within the string to check. /// /// # Return /// /// Returns `true` if the character at the specified offset is a space, tab, line break character, or null character, /// and `false` otherwise. #[macro_export] macro_rules! IS_BLANKZ_AT { ($string:expr, $offset:expr) => { IS_BLANK_AT!($string, $offset) || IS_BREAKZ_AT!($string, $offset) }; } /// Checks if the character at the current pointer in the given string is a space, tab, line break character, /// or if it is a null character. /// /// # Parameters /// /// * `string`: A reference to the string to check. /// /// # Return /// /// Returns `true` if the character is a space, tab, line break character, or null character, /// and `false` otherwise. #[macro_export] macro_rules! IS_BLANKZ { ($string:expr) => { IS_BLANKZ_AT!($string, 0) }; } /// Returns the width of a Unicode character at the given offset in a string. /// /// # Parameters /// /// * `string`: A reference to the string containing the Unicode characters. /// * `offset`: The offset in the string where the Unicode character is located. /// /// # Return /// /// The width of the Unicode character at the given offset. The width is determined by the first byte of the character: /// - If the first byte is 0x00-0x7F, the width is 1. /// - If the first byte is 0xC0-0xDF, the width is 2. /// - If the first byte is 0xE0-0xEF, the width is 3. /// - If the first byte is 0xF0-0xF7, the width is 4. /// - If the first byte does not match any of the above patterns, the width is 0. #[macro_export] macro_rules! WIDTH_AT { ($string:expr, $offset:expr) => { if *$string.pointer.wrapping_offset($offset) & 0x80 == 0x00 { 1 } else if *$string.pointer.wrapping_offset($offset) & 0xE0 == 0xC0 { 2 } else if *$string.pointer.wrapping_offset($offset) & 0xF0 == 0xE0 { 3 } else if *$string.pointer.wrapping_offset($offset) & 0xF8 == 0xF0 { 4 } else { 0 } }; } /// Returns the width of the Unicode character at the current position in a string. /// /// This macro calculates the width of the Unicode character that the `pointer` in the given string is currently pointing to. /// The width is determined by checking the first byte of the character at the current position in the string, using the /// `WIDTH_AT!` macro with an offset of `0`. /// /// # Parameters /// /// * `string`: A reference to a struct containing a `pointer` field that points to a byte in a string. /// This byte is expected to be the start of a Unicode character. /// /// # Return /// /// The width of the Unicode character at the current position of the `pointer` in the string: /// /// - If the first byte is in the range `0x00` to `0x7F`, the width is 1 byte. /// - If the first byte is in the range `0xC0` to `0xDF`, the width is 2 bytes. /// - If the first byte is in the range `0xE0` to `0xEF`, the width is 3 bytes. /// - If the first byte is in the range `0xF0` to `0xF7`, the width is 4 bytes. /// - If the first byte does not match any of the above patterns, the width is 0, indicating an invalid or unsupported character. /// /// # Safety /// /// The caller must ensure that the `pointer` in the `string` is pointing to valid memory and that the memory contains a valid Unicode sequence. /// Using this macro on an invalid or corrupted string may result in undefined behavior or incorrect results. #[macro_export] macro_rules! WIDTH { ($string:expr) => { WIDTH_AT!($string, 0) }; } /// Moves the pointer of the given string to the next Unicode character. /// /// This macro moves the pointer of the given string to the next Unicode character, /// taking into account the width of the Unicode character. The width is determined /// by the first byte of the character. /// /// # Parameters /// /// * `string`: A mutable reference to the string whose pointer will be moved. /// /// # Return /// /// This macro does not return a value. It moves the pointer of the given string /// to the next Unicode character. #[macro_export] macro_rules! MOVE { ($string:expr) => { $string.pointer = $string.pointer.wrapping_offset(WIDTH!($string)) }; } /// Copies the content of a string to another string. /// /// This macro copies the content of a string to another string. It handles different Unicode character /// encodings by checking the first byte of the character. If the character is a single-byte character, it /// is copied directly. If the character is a multi-byte character, it is copied byte by byte. /// /// # Parameters /// /// * `string_a`: A mutable reference to the destination string where the content will be copied. /// * `string_b`: A mutable reference to the source string from which the content will be copied. /// /// # Return /// /// This macro does not return a value. It copies the content of a string to another string. #[macro_export] macro_rules! copy { ($string_a:expr, $string_b:expr) => { if *$string_b.pointer & 0x80 == 0x00 { *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); } else if *$string_b.pointer & 0xE0 == 0xC0 { *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); } else if *$string_b.pointer & 0xF0 == 0xE0 { *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); } else if *$string_b.pointer & 0xF8 == 0xF0 { *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); *$string_a.pointer = *$string_b.pointer; $string_a.pointer = $string_a.pointer.wrapping_offset(1); $string_b.pointer = $string_b.pointer.wrapping_offset(1); } }; } // ------------------------------------ // Stack Management Macros // ------------------------------------ /// Initializes a stack with a specified type and allocates memory for it. /// /// # Parameters /// /// * `stack`: A mutable reference to the stack to be initialized. /// * `type`: The type of elements that will be stored in the stack. /// /// # Return /// /// This function does not return a value. It initializes the stack with the given type and allocates memory for it. /// The memory is allocated using the `yaml_malloc` function, and the start, top, and end pointers of the stack are set accordingly. #[macro_export] macro_rules! STACK_INIT { ($stack:expr, $type:ty) => {{ $stack.start = yaml_malloc(16 * size_of::<$type>() as libc::c_ulong) as *mut $type; $stack.top = $stack.start; $stack.end = $stack.start.offset(16_isize); }}; } /// Deallocates the memory used by the stack and sets all pointers to null. /// /// # Parameters /// /// * `stack`: A mutable reference to the stack to be deallocated. /// /// # Return /// /// This function does not return a value. It deallocates the memory used by the stack and sets all pointers to null. #[macro_export] macro_rules! STACK_DEL { ($stack:expr) => { yaml_free($stack.start as *mut libc::c_void); $stack.end = ptr::null_mut(); $stack.top = ptr::null_mut(); $stack.start = ptr::null_mut(); }; } /// Checks if the stack has no elements. /// /// This macro checks if the stack has no elements by comparing the start and top pointers. /// If the start and top pointers are equal, it means the stack is empty and the function returns `true`. /// Otherwise, it means the stack has elements and the function returns `false`. /// /// # Parameters /// /// * `stack`: A mutable reference to the stack to be checked. /// /// # Return /// /// * `true` if the stack is empty, i.e., the start and top pointers are equal. /// * `false` if the stack is not empty, i.e., the start and top pointers are not equal. #[macro_export] macro_rules! STACK_EMPTY { ($stack:expr) => { $stack.start == $stack.top }; } /// Checks if the stack has enough memory to push a new element. /// /// This macro checks if the stack has enough memory to push a new element by comparing the distance /// between the top and start pointers with the maximum allowed distance. If the distance is less than /// the maximum allowed distance minus one, it means the stack has enough memory and the function /// returns `OK`. Otherwise, it sets the error field of the context to `YamlMemoryError` and returns /// `FAIL`. /// /// # Parameters /// /// * `$context`: A mutable reference to the context in which the stack is being used. /// * `$stack`: A mutable reference to the stack being checked. /// /// # Return /// /// * `OK` if the stack has enough memory to push a new element. /// * `FAIL` if the stack does not have enough memory to push a new element. #[macro_export] macro_rules! STACK_LIMIT { ($context:expr, $stack:expr) => { if $stack.top.c_offset_from($stack.start) < libc::c_int::MAX as isize - 1 { OK } else { (*$context).error = YamlMemoryError; FAIL } }; } /// Pushes a value onto the stack. /// /// This macro pushes a value onto the stack. If the stack is full, it extends the stack by allocating /// additional memory. /// /// # Parameters /// /// * `stack`: A mutable reference to the stack onto which the value will be pushed. /// * `value`: The value to be pushed onto the stack. /// /// # Return /// /// This macro does not return a value. It pushes the value onto the stack. #[macro_export] macro_rules! PUSH { (do $stack:expr, $push:expr) => {{ if $stack.top == $stack.end { yaml_stack_extend( addr_of_mut!($stack.start) as *mut *mut libc::c_void, addr_of_mut!($stack.top) as *mut *mut libc::c_void, addr_of_mut!($stack.end) as *mut *mut libc::c_void, ); } $push; $stack.top = $stack.top.wrapping_offset(1); }}; ($stack:expr, *$value:expr) => { PUSH!(do $stack, ptr::copy_nonoverlapping($value, $stack.top, 1)) }; ($stack:expr, $value:expr) => { PUSH!(do $stack, ptr::write($stack.top, $value)) }; } /// Removes and returns the last element from the stack. /// /// # Parameters /// /// * `stack`: A mutable reference to the stack from which the last element will be removed. /// /// # Return /// /// * The last element from the stack. #[macro_export] macro_rules! POP { ($stack:expr) => { *{ $stack.top = $stack.top.offset(-1); $stack.top } }; } // ------------------------------------ // Queue Management Macros // ------------------------------------ /// Initializes a queue with a specified type and allocates memory for it. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue to be initialized. /// * `type`: The type of elements that will be stored in the queue. /// /// # Return /// /// This function does not return a value. It initializes the queue with the given type and allocates memory for it. #[macro_export] macro_rules! QUEUE_INIT { ($queue:expr, $type:ty) => {{ $queue.start = yaml_malloc(16 * size_of::<$type>() as libc::c_ulong) as *mut $type; $queue.tail = $queue.start; $queue.head = $queue.tail; $queue.end = $queue.start.offset(16_isize); }}; } /// Deallocates the memory used by the queue and sets all pointers to null. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue to be deallocated. /// /// # Return /// /// This function does not return a value. #[macro_export] macro_rules! QUEUE_DEL { ($queue:expr) => { yaml_free($queue.start as *mut libc::c_void); $queue.end = ptr::null_mut(); $queue.tail = ptr::null_mut(); $queue.head = ptr::null_mut(); $queue.start = ptr::null_mut(); }; } /// Checks if the queue is empty. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue to be checked. /// /// # Return /// /// * `true` if the queue is empty, i.e., the head and tail pointers are equal. /// * `false` if the queue is not empty, i.e., the head and tail pointers are not equal. #[macro_export] macro_rules! QUEUE_EMPTY { ($queue:expr) => { $queue.head == $queue.tail }; } /// Enqueues a value onto the queue. /// /// This macro enqueues a value onto the queue. If the queue is full, it extends the queue by allocating additional memory. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue onto which the value will be enqueued. /// * `value`: The value to be enqueued onto the queue. This can be a reference or a direct value. /// /// # Return /// /// This macro does not return a value. It enqueues the value onto the queue. #[macro_export] macro_rules! ENQUEUE { (do $queue:expr, $enqueue:expr) => {{ if $queue.tail == $queue.end { yaml_queue_extend( addr_of_mut!($queue.start) as *mut *mut libc::c_void, addr_of_mut!($queue.head) as *mut *mut libc::c_void, addr_of_mut!($queue.tail) as *mut *mut libc::c_void, addr_of_mut!($queue.end) as *mut *mut libc::c_void, ); } $enqueue; $queue.tail = $queue.tail.wrapping_offset(1); }}; ($queue:expr, *$value:expr) => { ENQUEUE!(do $queue, ptr::copy_nonoverlapping($value, $queue.tail, 1)) }; ($queue:expr, $value:expr) => { ENQUEUE!(do $queue, ptr::write($queue.tail, $value)) }; } /// Removes and returns the first element from the queue. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue from which the first element will be removed. /// /// # Return /// /// * The first element from the queue. #[macro_export] macro_rules! DEQUEUE { ($queue:expr) => { *{ let head = $queue.head; $queue.head = $queue.head.wrapping_offset(1); head } }; } /// Inserts a value into the queue at the specified index. /// /// # Parameters /// /// * `queue`: A mutable reference to the queue where the value will be inserted. /// * `index`: The index at which the value will be inserted. /// * `value`: The value to be inserted into the queue. /// /// # Return /// /// This macro does not return a value. #[macro_export] macro_rules! QUEUE_INSERT { ($queue:expr, $index:expr, $value:expr) => {{ if $queue.tail == $queue.end { yaml_queue_extend( addr_of_mut!($queue.start) as *mut *mut libc::c_void, addr_of_mut!($queue.head) as *mut *mut libc::c_void, addr_of_mut!($queue.tail) as *mut *mut libc::c_void, addr_of_mut!($queue.end) as *mut *mut libc::c_void, ); } let _ = memmove( $queue .head .wrapping_offset($index as isize) .wrapping_offset(1_isize) as *mut libc::c_void, $queue.head.wrapping_offset($index as isize) as *const libc::c_void, ($queue.tail.c_offset_from($queue.head) as libc::c_ulong) .wrapping_sub($index) .wrapping_mul(size_of::() as libc::c_ulong), ); *$queue.head.wrapping_offset($index as isize) = $value; let fresh14 = addr_of_mut!($queue.tail); *fresh14 = (*fresh14).wrapping_offset(1); }}; } libyml-0.0.5/src/memory.rs000064400000000000000000000133611046102023000135670ustar 00000000000000use crate::{ externs::{free, malloc, realloc, strlen}, libc, yaml::{size_t, yaml_char_t}, }; use core::{mem::size_of, ptr}; use libc::c_void; /// Allocate memory using the system's `malloc` function. /// /// This function allocates `size` bytes of uninitialized memory and returns a pointer to it. /// /// # Arguments /// /// * `size` - The number of bytes to allocate. /// /// # Returns /// /// Returns a pointer to the allocated memory, or a null pointer if the allocation failed. /// /// # Safety /// /// This function is unsafe because: /// - It directly calls the system's `malloc` function, which is not memory-safe. /// - The caller must ensure that the allocated memory is properly freed using `yaml_free`. /// - The caller is responsible for initializing the allocated memory before use. /// /// # Examples /// /// ``` /// use libyml::memory::yaml_malloc; /// use libyml::yaml::size_t; /// use libyml::memory::yaml_free; /// /// unsafe { /// let size: size_t = 1024; /// let ptr = yaml_malloc(size); /// if !ptr.is_null() { /// // Use the allocated memory /// // ... /// yaml_free(ptr); /// } /// } /// ``` pub unsafe fn yaml_malloc(size: size_t) -> *mut c_void { malloc(size) } /// Reallocate memory using the system's `realloc` function. /// /// This function changes the size of the memory block pointed to by `ptr` to `size` bytes. /// /// # Arguments /// /// * `ptr` - A pointer to the memory block to reallocate. If null, this function behaves like `yaml_malloc`. /// * `size` - The new size of the memory block in bytes. /// /// # Returns /// /// Returns a pointer to the reallocated memory, which may be different from `ptr`, or a null pointer if the reallocation failed. /// /// # Safety /// /// This function is unsafe because: /// - It directly calls the system's `realloc` function, which is not memory-safe. /// - The caller must ensure that `ptr` is either null or was previously allocated by `yaml_malloc` or `yaml_realloc`. /// - The caller must ensure that the reallocated memory is properly freed using `yaml_free`. /// - The contents of the reallocated memory beyond the original size are undefined. /// /// # Note /// /// If the reallocation fails, the original memory block is left untouched and a null pointer is returned. /// /// # Examples /// /// ``` /// use libyml::memory::{yaml_malloc, yaml_realloc, yaml_free}; /// use libyml::yaml::size_t; /// /// unsafe { /// let mut size: size_t = 1024; /// let mut ptr = yaml_malloc(size); /// if !ptr.is_null() { /// // Use the allocated memory /// // ... /// size = 2048; /// ptr = yaml_realloc(ptr, size); /// if !ptr.is_null() { /// // Use the reallocated memory /// // ... /// yaml_free(ptr); /// } /// } /// } /// ``` pub unsafe fn yaml_realloc( ptr: *mut c_void, size: size_t, ) -> *mut c_void { if !ptr.is_null() { realloc(ptr, size) } else { malloc(size) } } /// Free memory allocated by `yaml_malloc` or `yaml_realloc`. /// /// This function deallocates the memory previously allocated by `yaml_malloc` or `yaml_realloc`. /// /// # Arguments /// /// * `ptr` - A pointer to the memory block to free. If null, no operation is performed. /// /// # Safety /// /// This function is unsafe because: /// - It directly calls the system's `free` function, which is not memory-safe. /// - The caller must ensure that `ptr` was allocated by `yaml_malloc` or `yaml_realloc`. /// - After calling this function, `ptr` becomes invalid and must not be used. /// /// # Examples /// /// ``` /// use libyml::memory::{yaml_malloc, yaml_free}; /// use libyml::yaml::size_t; /// /// unsafe { /// let size: size_t = 1024; /// let ptr = yaml_malloc(size); /// if !ptr.is_null() { /// // Use the allocated memory /// // ... /// yaml_free(ptr); /// // ptr is now invalid and must not be used /// } /// } /// ``` pub unsafe fn yaml_free(ptr: *mut c_void) { if !ptr.is_null() { free(ptr); } } /// Duplicate a string using the system's `malloc` function and manual copy due to type mismatch. /// /// This function creates a new copy of the input string, allocating new memory for it. /// /// # Arguments /// /// * `str` - A pointer to the null-terminated string to duplicate. /// /// # Returns /// /// Returns a pointer to the newly allocated string, or a null pointer if the allocation failed or the input was null. /// /// # Safety /// /// This function is unsafe because: /// - It involves memory allocation and raw pointer manipulation. /// - The caller must ensure that `str` is a valid, null-terminated string. /// - The caller is responsible for freeing the returned pointer using `yaml_free`. /// /// # Examples /// /// ``` /// use libyml::memory::{yaml_strdup, yaml_free}; /// use libyml::yaml::yaml_char_t; /// use core::ffi::c_void; /// /// unsafe { /// // Note: The cast to *const yaml_char_t is necessary because yaml_char_t /// // might not be the same as u8 on all systems. /// let original: *const yaml_char_t = b"Hello, world!\0".as_ptr() as *const yaml_char_t; /// let copy = yaml_strdup(original); /// if !copy.is_null() { /// // Use the duplicated string /// // ... /// yaml_free(copy as *mut c_void); /// } /// } /// ``` pub unsafe fn yaml_strdup(str: *const yaml_char_t) -> *mut yaml_char_t { if str.is_null() { return ptr::null_mut(); } let len = strlen(str as *const libc::c_char) as usize; let new_size = (len + 1) * size_of::(); let new_str = malloc(new_size.try_into().unwrap()) as *mut yaml_char_t; if new_str.is_null() { return ptr::null_mut(); } ptr::copy_nonoverlapping(str, new_str, len + 1); new_str } libyml-0.0.5/src/ops.rs000064400000000000000000000055311046102023000130600ustar 00000000000000pub(crate) trait ForceAdd: Sized { fn force_add(self, rhs: Self) -> Self; } impl ForceAdd for u8 { fn force_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(die) } } impl ForceAdd for i32 { fn force_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(die) } } impl ForceAdd for u32 { fn force_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(die) } } impl ForceAdd for u64 { fn force_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(die) } } impl ForceAdd for usize { fn force_add(self, rhs: Self) -> Self { self.checked_add(rhs).unwrap_or_else(die) } } pub(crate) trait ForceMul: Sized { fn force_mul(self, rhs: Self) -> Self; } impl ForceMul for i32 { fn force_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or_else(die) } } impl ForceMul for i64 { fn force_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or_else(die) } } impl ForceMul for u64 { fn force_mul(self, rhs: Self) -> Self { self.checked_mul(rhs).unwrap_or_else(die) } } pub(crate) trait ForceInto { fn force_into(self) -> U where Self: TryInto; } impl ForceInto for T { fn force_into(self) -> U where Self: TryInto, { >::try_into(self) .ok() .unwrap_or_else(die) } } // Deterministically abort on arithmetic overflow, instead of wrapping and // continuing with invalid behavior. // // This is impossible or nearly impossible to hit as the arithmetic computations // in libyaml are all related to either: // // - small integer processing (ascii, hex digits) // - allocation sizing // // and the only allocations in libyaml are for fixed-sized objects and // geometrically growing buffers with a growth factor of 2. So in order for an // allocation computation to overflow usize, the previous allocation for that // container must have been filled to a size of usize::MAX/2, which is an // allocation that would have failed in the allocator. But we check for this to // be pedantic and to find out if it ever does happen. // // No-std abort is implemented using a double panic. On most platforms the // current mechanism for this is for core::intrinsics::abort to invoke an // invalid instruction. On Unix, the process will probably terminate with a // signal like SIGABRT, SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise // behaviour is not guaranteed and not stable, but is safe. #[cold] pub(crate) fn die() -> T { struct PanicAgain; impl Drop for PanicAgain { fn drop(&mut self) { panic!("arithmetic overflow"); } } fn do_die() -> ! { let _panic_again = PanicAgain; panic!("arithmetic overflow"); } do_die(); } libyml-0.0.5/src/parser.rs000064400000000000000000001614311046102023000135550ustar 00000000000000use crate::externs::{memcpy, memset, strcmp, strlen}; use crate::internal::yaml_stack_extend; use crate::memory::{yaml_free, yaml_malloc, yaml_strdup}; use crate::ops::ForceAdd as _; use crate::scanner::yaml_parser_fetch_more_tokens; use crate::success::{Success, FAIL, OK}; use crate::yaml::{size_t, yaml_char_t}; use crate::{ libc, YamlAliasEvent, YamlAliasToken, YamlAnchorToken, YamlBlockEndToken, YamlBlockEntryToken, YamlBlockMappingStartToken, YamlBlockMappingStyle, YamlBlockSequenceStartToken, YamlBlockSequenceStyle, YamlDocumentEndEvent, YamlDocumentEndToken, YamlDocumentStartEvent, YamlDocumentStartToken, YamlEventT, YamlFlowEntryToken, YamlFlowMappingEndToken, YamlFlowMappingStartToken, YamlFlowMappingStyle, YamlFlowSequenceEndToken, YamlFlowSequenceStartToken, YamlFlowSequenceStyle, YamlKeyToken, YamlMappingEndEvent, YamlMappingStartEvent, YamlMarkT, YamlNoError, YamlParseBlockMappingFirstKeyState, YamlParseBlockMappingKeyState, YamlParseBlockMappingValueState, YamlParseBlockNodeOrIndentlessSequenceState, YamlParseBlockNodeState, YamlParseBlockSequenceEntryState, YamlParseBlockSequenceFirstEntryState, YamlParseDocumentContentState, YamlParseDocumentEndState, YamlParseDocumentStartState, YamlParseEndState, YamlParseFlowMappingEmptyValueState, YamlParseFlowMappingFirstKeyState, YamlParseFlowMappingKeyState, YamlParseFlowMappingValueState, YamlParseFlowNodeState, YamlParseFlowSequenceEntryMappingEndState, YamlParseFlowSequenceEntryMappingKeyState, YamlParseFlowSequenceEntryMappingValueState, YamlParseFlowSequenceEntryState, YamlParseFlowSequenceFirstEntryState, YamlParseImplicitDocumentStartState, YamlParseIndentlessSequenceEntryState, YamlParseStreamStartState, YamlParserError, YamlParserT, YamlPlainScalarStyle, YamlScalarEvent, YamlScalarToken, YamlSequenceEndEvent, YamlSequenceStartEvent, YamlStreamEndEvent, YamlStreamEndToken, YamlStreamStartEvent, YamlStreamStartToken, YamlTagDirectiveT, YamlTagDirectiveToken, YamlTagToken, YamlTokenT, YamlValueToken, YamlVersionDirectiveT, YamlVersionDirectiveToken, }; use core::mem::size_of; use core::ptr::{self, addr_of_mut}; unsafe fn peek_token(parser: *mut YamlParserT) -> *mut YamlTokenT { if (*parser).token_available || yaml_parser_fetch_more_tokens(parser).ok { (*parser).tokens.head } else { ptr::null_mut::() } } unsafe fn skip_token(parser: *mut YamlParserT) { (*parser).token_available = false; let fresh3 = addr_of_mut!((*parser).tokens_parsed); *fresh3 = (*fresh3).wrapping_add(1); (*parser).stream_end_produced = (*(*parser).tokens.head).type_ == YamlStreamEndToken; let fresh4 = addr_of_mut!((*parser).tokens.head); *fresh4 = (*fresh4).wrapping_offset(1); } /// Parse the input stream and produce the next parsing event. /// /// This function should be called repeatedly to produce a sequence of events /// corresponding to the input stream. The initial event will be of type /// `YamlStreamStartEvent`, and the final event will be of type `YamlStreamEndEvent`. /// /// # Safety /// /// This function is unsafe because: /// - It operates on raw pointers. /// - It assumes certain memory layouts and alignments. /// - It may cause undefined behavior if the input pointers are invalid or if the /// function is misused. /// /// # Arguments /// /// * `parser` - A pointer to a properly initialized `YamlParserT` struct. /// * `event` - A pointer to a `YamlEventT` struct that will be filled with the next event. /// /// # Returns /// /// Returns `OK` if an event was successfully parsed, or `FAIL` if: /// - The stream has ended (stream_end_produced is true) /// - There's an existing error in the parser /// - The parser is in the end state /// /// # Errors /// /// This function will return `FAIL` if any of the above error conditions are met. /// The caller should check the parser's error state for more details on the failure. /// /// # Notes /// /// - The caller is responsible for freeing any buffers associated with the produced /// event using the `yaml_event_delete()` function. /// - Do not alternate calls to `yaml_parser_parse()` with calls to `yaml_parser_scan()` /// or `yaml_parser_load()`. Doing so will break the parser. /// pub unsafe fn yaml_parser_parse( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { __assert!(!parser.is_null()); __assert!(!event.is_null()); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); if (*parser).stream_end_produced { return FAIL; } if (*parser).error != YamlNoError { return FAIL; } if (*parser).state == YamlParseEndState { return FAIL; } yaml_parser_state_machine(parser, event) } unsafe fn yaml_parser_set_parser_error( parser: *mut YamlParserT, problem: *const libc::c_char, problem_mark: YamlMarkT, ) { (*parser).error = YamlParserError; let fresh0 = addr_of_mut!((*parser).problem); *fresh0 = problem; (*parser).problem_mark = problem_mark; } unsafe fn yaml_parser_set_parser_error_context( parser: *mut YamlParserT, context: *const libc::c_char, context_mark: YamlMarkT, problem: *const libc::c_char, problem_mark: YamlMarkT, ) { (*parser).error = YamlParserError; let fresh1 = addr_of_mut!((*parser).context); *fresh1 = context; (*parser).context_mark = context_mark; let fresh2 = addr_of_mut!((*parser).problem); *fresh2 = problem; (*parser).problem_mark = problem_mark; } unsafe fn yaml_parser_state_machine( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { match (*parser).state { YamlParseStreamStartState => { yaml_parser_parse_stream_start(parser, event) } YamlParseImplicitDocumentStartState => { yaml_parser_parse_document_start(parser, event, true) } YamlParseDocumentStartState => { yaml_parser_parse_document_start(parser, event, false) } YamlParseDocumentContentState => { yaml_parser_parse_document_content(parser, event) } YamlParseDocumentEndState => { yaml_parser_parse_document_end(parser, event) } YamlParseBlockNodeState => { yaml_parser_parse_node(parser, event, true, false) } YamlParseBlockNodeOrIndentlessSequenceState => { yaml_parser_parse_node(parser, event, true, true) } YamlParseFlowNodeState => { yaml_parser_parse_node(parser, event, false, false) } YamlParseBlockSequenceFirstEntryState => { yaml_parser_parse_block_sequence_entry(parser, event, true) } YamlParseBlockSequenceEntryState => { yaml_parser_parse_block_sequence_entry(parser, event, false) } YamlParseIndentlessSequenceEntryState => { yaml_parser_parse_indentless_sequence_entry(parser, event) } YamlParseBlockMappingFirstKeyState => { yaml_parser_parse_block_mapping_key(parser, event, true) } YamlParseBlockMappingKeyState => { yaml_parser_parse_block_mapping_key(parser, event, false) } YamlParseBlockMappingValueState => { yaml_parser_parse_block_mapping_value(parser, event) } YamlParseFlowSequenceFirstEntryState => { yaml_parser_parse_flow_sequence_entry(parser, event, true) } YamlParseFlowSequenceEntryState => { yaml_parser_parse_flow_sequence_entry(parser, event, false) } YamlParseFlowSequenceEntryMappingKeyState => { yaml_parser_parse_flow_sequence_entry_mapping_key( parser, event, ) } YamlParseFlowSequenceEntryMappingValueState => { yaml_parser_parse_flow_sequence_entry_mapping_value( parser, event, ) } YamlParseFlowSequenceEntryMappingEndState => { yaml_parser_parse_flow_sequence_entry_mapping_end( parser, event, ) } YamlParseFlowMappingFirstKeyState => { yaml_parser_parse_flow_mapping_key(parser, event, true) } YamlParseFlowMappingKeyState => { yaml_parser_parse_flow_mapping_key(parser, event, false) } YamlParseFlowMappingValueState => { yaml_parser_parse_flow_mapping_value(parser, event, false) } YamlParseFlowMappingEmptyValueState => { yaml_parser_parse_flow_mapping_value(parser, event, true) } _ => FAIL, } } unsafe fn yaml_parser_parse_stream_start( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let token: *mut YamlTokenT = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlStreamStartToken { yaml_parser_set_parser_error( parser, b"did not find expected \0" as *const u8 as *const libc::c_char, (*token).start_mark, ); return FAIL; } (*parser).state = YamlParseImplicitDocumentStartState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlStreamStartEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).start_mark; (*event).data.stream_start.encoding = (*token).data.stream_start.encoding; skip_token(parser); OK } unsafe fn yaml_parser_parse_document_start( parser: *mut YamlParserT, event: *mut YamlEventT, implicit: bool, ) -> Success { let mut token: *mut YamlTokenT; let mut version_directive: *mut YamlVersionDirectiveT = ptr::null_mut::(); struct TagDirectives { start: *mut YamlTagDirectiveT, end: *mut YamlTagDirectiveT, } let mut tag_directives = TagDirectives { start: ptr::null_mut::(), end: ptr::null_mut::(), }; token = peek_token(parser); if token.is_null() { return FAIL; } if !implicit { while (*token).type_ == YamlDocumentEndToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } } } if implicit && (*token).type_ != YamlVersionDirectiveToken && (*token).type_ != YamlTagDirectiveToken && (*token).type_ != YamlDocumentStartToken && (*token).type_ != YamlStreamEndToken { if yaml_parser_process_directives( parser, ptr::null_mut::<*mut YamlVersionDirectiveT>(), ptr::null_mut::<*mut YamlTagDirectiveT>(), ptr::null_mut::<*mut YamlTagDirectiveT>(), ) .fail { return FAIL; } PUSH!((*parser).states, YamlParseDocumentEndState); (*parser).state = YamlParseBlockNodeState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentStartEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).start_mark; let fresh9 = addr_of_mut!( (*event).data.document_start.version_directive ); *fresh9 = ptr::null_mut::(); let fresh10 = addr_of_mut!( (*event).data.document_start.tag_directives.start ); *fresh10 = ptr::null_mut::(); let fresh11 = addr_of_mut!( (*event).data.document_start.tag_directives.end ); *fresh11 = ptr::null_mut::(); (*event).data.document_start.implicit = true; OK } else if (*token).type_ != YamlStreamEndToken { let end_mark: YamlMarkT; let start_mark: YamlMarkT = (*token).start_mark; if yaml_parser_process_directives( parser, addr_of_mut!(version_directive), addr_of_mut!(tag_directives.start), addr_of_mut!(tag_directives.end), ) .fail { return FAIL; } token = peek_token(parser); if !token.is_null() { if (*token).type_ != YamlDocumentStartToken { yaml_parser_set_parser_error( parser, b"did not find expected \0" as *const u8 as *const libc::c_char, (*token).start_mark, ); } else { PUSH!((*parser).states, YamlParseDocumentEndState); (*parser).state = YamlParseDocumentContentState; end_mark = (*token).end_mark; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh14 = addr_of_mut!( (*event).data.document_start.version_directive ); *fresh14 = version_directive; let fresh15 = addr_of_mut!( (*event).data.document_start.tag_directives.start ); *fresh15 = tag_directives.start; let fresh16 = addr_of_mut!( (*event).data.document_start.tag_directives.end ); *fresh16 = tag_directives.end; (*event).data.document_start.implicit = false; skip_token(parser); tag_directives.end = ptr::null_mut::(); tag_directives.start = tag_directives.end; return OK; } } yaml_free(version_directive as *mut libc::c_void); while tag_directives.start != tag_directives.end { yaml_free( (*tag_directives.end.wrapping_offset(-1_isize)).handle as *mut libc::c_void, ); yaml_free( (*tag_directives.end.wrapping_offset(-1_isize)).prefix as *mut libc::c_void, ); tag_directives.end = tag_directives.end.wrapping_offset(-1); } yaml_free(tag_directives.start as *mut libc::c_void); FAIL } else { (*parser).state = YamlParseEndState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlStreamEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; skip_token(parser); OK } } unsafe fn yaml_parser_parse_document_content( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let token: *mut YamlTokenT = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlVersionDirectiveToken || (*token).type_ == YamlTagDirectiveToken || (*token).type_ == YamlDocumentStartToken || (*token).type_ == YamlDocumentEndToken || (*token).type_ == YamlStreamEndToken { (*parser).state = POP!((*parser).states); yaml_parser_process_empty_scalar(event, (*token).start_mark) } else { yaml_parser_parse_node(parser, event, true, false) } } unsafe fn yaml_parser_parse_document_end( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let mut end_mark: YamlMarkT; let mut implicit = true; let token: *mut YamlTokenT = peek_token(parser); if token.is_null() { return FAIL; } end_mark = (*token).start_mark; let start_mark: YamlMarkT = end_mark; if (*token).type_ == YamlDocumentEndToken { end_mark = (*token).end_mark; skip_token(parser); implicit = false; } while !STACK_EMPTY!((*parser).tag_directives) { let tag_directive = POP!((*parser).tag_directives); yaml_free(tag_directive.handle as *mut libc::c_void); yaml_free(tag_directive.prefix as *mut libc::c_void); } (*parser).state = YamlParseDocumentStartState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlDocumentEndEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; (*event).data.document_end.implicit = implicit; OK } unsafe fn yaml_parser_parse_node( parser: *mut YamlParserT, event: *mut YamlEventT, block: bool, indentless_sequence: bool, ) -> Success { let mut current_block: u64; let mut token: *mut YamlTokenT; let mut anchor: *mut yaml_char_t = ptr::null_mut::(); let mut tag_handle: *mut yaml_char_t = ptr::null_mut::(); let mut tag_suffix: *mut yaml_char_t = ptr::null_mut::(); let mut tag: *mut yaml_char_t = ptr::null_mut::(); let mut start_mark: YamlMarkT; let mut end_mark: YamlMarkT; let mut tag_mark = YamlMarkT { index: 0, line: 0, column: 0, }; let implicit; token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlAliasToken { (*parser).state = POP!((*parser).states); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlAliasEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; let fresh26 = addr_of_mut!((*event).data.alias.anchor); *fresh26 = (*token).data.alias.value; skip_token(parser); OK } else { end_mark = (*token).start_mark; start_mark = end_mark; if (*token).type_ == YamlAnchorToken { anchor = (*token).data.anchor.value; start_mark = (*token).start_mark; end_mark = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { current_block = 17786380918591080555; } else if (*token).type_ == YamlTagToken { tag_handle = (*token).data.tag.handle; tag_suffix = (*token).data.tag.suffix; tag_mark = (*token).start_mark; end_mark = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { current_block = 17786380918591080555; } else { current_block = 11743904203796629665; } } else { current_block = 11743904203796629665; } } else if (*token).type_ == YamlTagToken { tag_handle = (*token).data.tag.handle; tag_suffix = (*token).data.tag.suffix; tag_mark = (*token).start_mark; start_mark = tag_mark; end_mark = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { current_block = 17786380918591080555; } else if (*token).type_ == YamlAnchorToken { anchor = (*token).data.anchor.value; end_mark = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { current_block = 17786380918591080555; } else { current_block = 11743904203796629665; } } else { current_block = 11743904203796629665; } } else { current_block = 11743904203796629665; } if current_block == 11743904203796629665 { if !tag_handle.is_null() { if *tag_handle == 0 { tag = tag_suffix; yaml_free(tag_handle as *mut libc::c_void); tag_suffix = ptr::null_mut::(); tag_handle = tag_suffix; current_block = 9437013279121998969; } else { let mut tag_directive: *mut YamlTagDirectiveT; tag_directive = (*parser).tag_directives.start; loop { if tag_directive == (*parser).tag_directives.top { current_block = 17728966195399430138; break; } if strcmp( (*tag_directive).handle as *mut libc::c_char, tag_handle as *mut libc::c_char, ) == 0 { let prefix_len: size_t = strlen( (*tag_directive).prefix as *mut libc::c_char, ); let suffix_len: size_t = strlen(tag_suffix as *mut libc::c_char); tag = yaml_malloc( prefix_len .force_add(suffix_len) .force_add(1_u64), ) as *mut yaml_char_t; let _ = memcpy( tag as *mut libc::c_void, (*tag_directive).prefix as *const libc::c_void, prefix_len, ); let _ = memcpy( tag.wrapping_offset(prefix_len as isize) as *mut libc::c_void, tag_suffix as *const libc::c_void, suffix_len, ); *tag.wrapping_offset( prefix_len.force_add(suffix_len) as isize, ) = b'\0'; yaml_free(tag_handle as *mut libc::c_void); yaml_free(tag_suffix as *mut libc::c_void); tag_suffix = ptr::null_mut::(); tag_handle = tag_suffix; current_block = 17728966195399430138; break; } else { tag_directive = tag_directive.wrapping_offset(1); } } if current_block != 17786380918591080555 { if tag.is_null() { yaml_parser_set_parser_error_context( parser, b"while parsing a node\0" as *const u8 as *const libc::c_char, start_mark, b"found undefined tag handle\0" as *const u8 as *const libc::c_char, tag_mark, ); current_block = 17786380918591080555; } else { current_block = 9437013279121998969; } } } } else { current_block = 9437013279121998969; } if current_block != 17786380918591080555 { implicit = tag.is_null() || *tag == 0; if indentless_sequence && (*token).type_ == YamlBlockEntryToken { end_mark = (*token).end_mark; (*parser).state = YamlParseIndentlessSequenceEntryState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh37 = addr_of_mut!( (*event).data.sequence_start.anchor ); *fresh37 = anchor; let fresh38 = addr_of_mut!((*event).data.sequence_start.tag); *fresh38 = tag; (*event).data.sequence_start.implicit = implicit; (*event).data.sequence_start.style = YamlBlockSequenceStyle; return OK; } else if (*token).type_ == YamlScalarToken { let mut plain_implicit = false; let mut quoted_implicit = false; end_mark = (*token).end_mark; if (*token).data.scalar.style == YamlPlainScalarStyle && tag.is_null() || !tag.is_null() && strcmp( tag as *mut libc::c_char, b"!\0" as *const u8 as *const libc::c_char, ) == 0 { plain_implicit = true; } else if tag.is_null() { quoted_implicit = true; } (*parser).state = POP!((*parser).states); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlScalarEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh40 = addr_of_mut!((*event).data.scalar.anchor); *fresh40 = anchor; let fresh41 = addr_of_mut!((*event).data.scalar.tag); *fresh41 = tag; let fresh42 = addr_of_mut!((*event).data.scalar.value); *fresh42 = (*token).data.scalar.value; (*event).data.scalar.length = (*token).data.scalar.length; (*event).data.scalar.plain_implicit = plain_implicit; (*event).data.scalar.quoted_implicit = quoted_implicit; (*event).data.scalar.style = (*token).data.scalar.style; skip_token(parser); return OK; } else if (*token).type_ == YamlFlowSequenceStartToken { end_mark = (*token).end_mark; (*parser).state = YamlParseFlowSequenceFirstEntryState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh45 = addr_of_mut!( (*event).data.sequence_start.anchor ); *fresh45 = anchor; let fresh46 = addr_of_mut!((*event).data.sequence_start.tag); *fresh46 = tag; (*event).data.sequence_start.implicit = implicit; (*event).data.sequence_start.style = YamlFlowSequenceStyle; return OK; } else if (*token).type_ == YamlFlowMappingStartToken { end_mark = (*token).end_mark; (*parser).state = YamlParseFlowMappingFirstKeyState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh47 = addr_of_mut!( (*event).data.mapping_start.anchor ); *fresh47 = anchor; let fresh48 = addr_of_mut!((*event).data.mapping_start.tag); *fresh48 = tag; (*event).data.mapping_start.implicit = implicit; (*event).data.mapping_start.style = YamlFlowMappingStyle; return OK; } else if block && (*token).type_ == YamlBlockSequenceStartToken { end_mark = (*token).end_mark; (*parser).state = YamlParseBlockSequenceFirstEntryState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh49 = addr_of_mut!( (*event).data.sequence_start.anchor ); *fresh49 = anchor; let fresh50 = addr_of_mut!((*event).data.sequence_start.tag); *fresh50 = tag; (*event).data.sequence_start.implicit = implicit; (*event).data.sequence_start.style = YamlBlockSequenceStyle; return OK; } else if block && (*token).type_ == YamlBlockMappingStartToken { end_mark = (*token).end_mark; (*parser).state = YamlParseBlockMappingFirstKeyState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingStartEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh51 = addr_of_mut!( (*event).data.mapping_start.anchor ); *fresh51 = anchor; let fresh52 = addr_of_mut!((*event).data.mapping_start.tag); *fresh52 = tag; (*event).data.mapping_start.implicit = implicit; (*event).data.mapping_start.style = YamlBlockMappingStyle; return OK; } else if !anchor.is_null() || !tag.is_null() { let value: *mut yaml_char_t = yaml_malloc(1_u64) as *mut yaml_char_t; *value = b'\0'; (*parser).state = POP!((*parser).states); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlScalarEvent; (*event).start_mark = start_mark; (*event).end_mark = end_mark; let fresh54 = addr_of_mut!((*event).data.scalar.anchor); *fresh54 = anchor; let fresh55 = addr_of_mut!((*event).data.scalar.tag); *fresh55 = tag; let fresh56 = addr_of_mut!((*event).data.scalar.value); *fresh56 = value; (*event).data.scalar.length = 0_u64; (*event).data.scalar.plain_implicit = implicit; (*event).data.scalar.quoted_implicit = false; (*event).data.scalar.style = YamlPlainScalarStyle; return OK; } else { yaml_parser_set_parser_error_context( parser, if block { b"while parsing a block node\0" as *const u8 as *const libc::c_char } else { b"while parsing a flow node\0" as *const u8 as *const libc::c_char }, start_mark, b"did not find expected node content\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); } } } yaml_free(anchor as *mut libc::c_void); yaml_free(tag_handle as *mut libc::c_void); yaml_free(tag_suffix as *mut libc::c_void); yaml_free(tag as *mut libc::c_void); FAIL } } unsafe fn yaml_parser_parse_block_sequence_entry( parser: *mut YamlParserT, event: *mut YamlEventT, first: bool, ) -> Success { let mut token: *mut YamlTokenT; if first { token = peek_token(parser); PUSH!((*parser).marks, (*token).start_mark); skip_token(parser); } token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlBlockEntryToken { let mark: YamlMarkT = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlBlockEntryToken && (*token).type_ != YamlBlockEndToken { PUSH!((*parser).states, YamlParseBlockSequenceEntryState); yaml_parser_parse_node(parser, event, true, false) } else { (*parser).state = YamlParseBlockSequenceEntryState; yaml_parser_process_empty_scalar(event, mark) } } else if (*token).type_ == YamlBlockEndToken { (*parser).state = POP!((*parser).states); let _ = POP!((*parser).marks); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; skip_token(parser); OK } else { yaml_parser_set_parser_error_context( parser, b"while parsing a block collection\0" as *const u8 as *const libc::c_char, POP!((*parser).marks), b"did not find expected '-' indicator\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); FAIL } } unsafe fn yaml_parser_parse_indentless_sequence_entry( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let mut token: *mut YamlTokenT; token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlBlockEntryToken { let mark: YamlMarkT = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlBlockEntryToken && (*token).type_ != YamlKeyToken && (*token).type_ != YamlValueToken && (*token).type_ != YamlBlockEndToken { PUSH!( (*parser).states, YamlParseIndentlessSequenceEntryState ); yaml_parser_parse_node(parser, event, true, false) } else { (*parser).state = YamlParseIndentlessSequenceEntryState; yaml_parser_process_empty_scalar(event, mark) } } else { (*parser).state = POP!((*parser).states); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).start_mark; OK } } unsafe fn yaml_parser_parse_block_mapping_key( parser: *mut YamlParserT, event: *mut YamlEventT, first: bool, ) -> Success { let mut token: *mut YamlTokenT; if first { token = peek_token(parser); PUSH!((*parser).marks, (*token).start_mark); skip_token(parser); } token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlKeyToken { let mark: YamlMarkT = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlKeyToken && (*token).type_ != YamlValueToken && (*token).type_ != YamlBlockEndToken { PUSH!((*parser).states, YamlParseBlockMappingValueState); yaml_parser_parse_node(parser, event, true, true) } else { (*parser).state = YamlParseBlockMappingValueState; yaml_parser_process_empty_scalar(event, mark) } } else if (*token).type_ == YamlBlockEndToken { (*parser).state = POP!((*parser).states); let _ = POP!((*parser).marks); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; skip_token(parser); OK } else { yaml_parser_set_parser_error_context( parser, b"while parsing a block mapping\0" as *const u8 as *const libc::c_char, POP!((*parser).marks), b"did not find expected key\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); FAIL } } unsafe fn yaml_parser_parse_block_mapping_value( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let mut token: *mut YamlTokenT; token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlValueToken { let mark: YamlMarkT = (*token).end_mark; skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlKeyToken && (*token).type_ != YamlValueToken && (*token).type_ != YamlBlockEndToken { PUSH!((*parser).states, YamlParseBlockMappingKeyState); yaml_parser_parse_node(parser, event, true, true) } else { (*parser).state = YamlParseBlockMappingKeyState; yaml_parser_process_empty_scalar(event, mark) } } else { (*parser).state = YamlParseBlockMappingKeyState; yaml_parser_process_empty_scalar(event, (*token).start_mark) } } unsafe fn yaml_parser_parse_flow_sequence_entry( parser: *mut YamlParserT, event: *mut YamlEventT, first: bool, ) -> Success { let mut token: *mut YamlTokenT; if first { token = peek_token(parser); PUSH!((*parser).marks, (*token).start_mark); skip_token(parser); } token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlFlowSequenceEndToken { if !first { if (*token).type_ == YamlFlowEntryToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } } else { yaml_parser_set_parser_error_context( parser, b"while parsing a flow sequence\0" as *const u8 as *const libc::c_char, POP!((*parser).marks), b"did not find expected ',' or ']'\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); return FAIL; } } if (*token).type_ == YamlKeyToken { (*parser).state = YamlParseFlowSequenceEntryMappingKeyState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingStartEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; let fresh99 = addr_of_mut!((*event).data.mapping_start.anchor); *fresh99 = ptr::null_mut::(); let fresh100 = addr_of_mut!((*event).data.mapping_start.tag); *fresh100 = ptr::null_mut::(); (*event).data.mapping_start.implicit = true; (*event).data.mapping_start.style = YamlFlowMappingStyle; skip_token(parser); return OK; } else if (*token).type_ != YamlFlowSequenceEndToken { PUSH!((*parser).states, YamlParseFlowSequenceEntryState); return yaml_parser_parse_node(parser, event, false, false); } } (*parser).state = POP!((*parser).states); let _ = POP!((*parser).marks); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlSequenceEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; skip_token(parser); OK } unsafe fn yaml_parser_parse_flow_sequence_entry_mapping_key( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let token: *mut YamlTokenT = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlValueToken && (*token).type_ != YamlFlowEntryToken && (*token).type_ != YamlFlowSequenceEndToken { PUSH!( (*parser).states, YamlParseFlowSequenceEntryMappingValueState ); yaml_parser_parse_node(parser, event, false, false) } else { let mark: YamlMarkT = (*token).end_mark; skip_token(parser); (*parser).state = YamlParseFlowSequenceEntryMappingValueState; yaml_parser_process_empty_scalar(event, mark) } } unsafe fn yaml_parser_parse_flow_sequence_entry_mapping_value( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let mut token: *mut YamlTokenT; token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ == YamlValueToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlFlowEntryToken && (*token).type_ != YamlFlowSequenceEndToken { PUSH!( (*parser).states, YamlParseFlowSequenceEntryMappingEndState ); return yaml_parser_parse_node(parser, event, false, false); } } (*parser).state = YamlParseFlowSequenceEntryMappingEndState; yaml_parser_process_empty_scalar(event, (*token).start_mark) } unsafe fn yaml_parser_parse_flow_sequence_entry_mapping_end( parser: *mut YamlParserT, event: *mut YamlEventT, ) -> Success { let token: *mut YamlTokenT = peek_token(parser); if token.is_null() { return FAIL; } (*parser).state = YamlParseFlowSequenceEntryState; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).start_mark; OK } unsafe fn yaml_parser_parse_flow_mapping_key( parser: *mut YamlParserT, event: *mut YamlEventT, first: bool, ) -> Success { let mut token: *mut YamlTokenT; if first { token = peek_token(parser); PUSH!((*parser).marks, (*token).start_mark); skip_token(parser); } token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlFlowMappingEndToken { if !first { if (*token).type_ == YamlFlowEntryToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } } else { yaml_parser_set_parser_error_context( parser, b"while parsing a flow mapping\0" as *const u8 as *const libc::c_char, POP!((*parser).marks), b"did not find expected ',' or '}'\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); return FAIL; } } if (*token).type_ == YamlKeyToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlValueToken && (*token).type_ != YamlFlowEntryToken && (*token).type_ != YamlFlowMappingEndToken { PUSH!((*parser).states, YamlParseFlowMappingValueState); return yaml_parser_parse_node( parser, event, false, false, ); } else { (*parser).state = YamlParseFlowMappingValueState; return yaml_parser_process_empty_scalar( event, (*token).start_mark, ); } } else if (*token).type_ != YamlFlowMappingEndToken { PUSH!( (*parser).states, YamlParseFlowMappingEmptyValueState ); return yaml_parser_parse_node(parser, event, false, false); } } (*parser).state = POP!((*parser).states); let _ = POP!((*parser).marks); let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlMappingEndEvent; (*event).start_mark = (*token).start_mark; (*event).end_mark = (*token).end_mark; skip_token(parser); OK } unsafe fn yaml_parser_parse_flow_mapping_value( parser: *mut YamlParserT, event: *mut YamlEventT, empty: bool, ) -> Success { let mut token: *mut YamlTokenT; token = peek_token(parser); if token.is_null() { return FAIL; } if empty { (*parser).state = YamlParseFlowMappingKeyState; return yaml_parser_process_empty_scalar( event, (*token).start_mark, ); } if (*token).type_ == YamlValueToken { skip_token(parser); token = peek_token(parser); if token.is_null() { return FAIL; } if (*token).type_ != YamlFlowEntryToken && (*token).type_ != YamlFlowMappingEndToken { PUSH!((*parser).states, YamlParseFlowMappingKeyState); return yaml_parser_parse_node(parser, event, false, false); } } (*parser).state = YamlParseFlowMappingKeyState; yaml_parser_process_empty_scalar(event, (*token).start_mark) } unsafe fn yaml_parser_process_empty_scalar( event: *mut YamlEventT, mark: YamlMarkT, ) -> Success { let value: *mut yaml_char_t = yaml_malloc(1_u64) as *mut yaml_char_t; *value = b'\0'; let _ = memset( event as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*event).type_ = YamlScalarEvent; (*event).start_mark = mark; (*event).end_mark = mark; let fresh138 = addr_of_mut!((*event).data.scalar.anchor); *fresh138 = ptr::null_mut::(); let fresh139 = addr_of_mut!((*event).data.scalar.tag); *fresh139 = ptr::null_mut::(); let fresh140 = addr_of_mut!((*event).data.scalar.value); *fresh140 = value; (*event).data.scalar.length = 0_u64; (*event).data.scalar.plain_implicit = true; (*event).data.scalar.quoted_implicit = false; (*event).data.scalar.style = YamlPlainScalarStyle; OK } unsafe fn yaml_parser_process_directives( parser: *mut YamlParserT, version_directive_ref: *mut *mut YamlVersionDirectiveT, tag_directives_start_ref: *mut *mut YamlTagDirectiveT, tag_directives_end_ref: *mut *mut YamlTagDirectiveT, ) -> Success { let mut current_block: u64; let mut default_tag_directives: [YamlTagDirectiveT; 3] = [ YamlTagDirectiveT { handle: b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, prefix: b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, }, YamlTagDirectiveT { handle: b"!!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, prefix: b"tag:yaml.org,2002:\0" as *const u8 as *const libc::c_char as *mut yaml_char_t, }, YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }, ]; let mut default_tag_directive: *mut YamlTagDirectiveT; let mut version_directive: *mut YamlVersionDirectiveT = ptr::null_mut::(); struct TagDirectives { start: *mut YamlTagDirectiveT, end: *mut YamlTagDirectiveT, top: *mut YamlTagDirectiveT, } let mut tag_directives = TagDirectives { start: ptr::null_mut::(), end: ptr::null_mut::(), top: ptr::null_mut::(), }; let mut token: *mut YamlTokenT; STACK_INIT!(tag_directives, YamlTagDirectiveT); token = peek_token(parser); if !token.is_null() { loop { if !((*token).type_ == YamlVersionDirectiveToken || (*token).type_ == YamlTagDirectiveToken) { current_block = 16924917904204750491; break; } if (*token).type_ == YamlVersionDirectiveToken { if !version_directive.is_null() { yaml_parser_set_parser_error( parser, b"found duplicate %YAML directive\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); current_block = 17143798186130252483; break; } else if (*token).data.version_directive.major != 1 || (*token).data.version_directive.minor != 1 && (*token).data.version_directive.minor != 2 { yaml_parser_set_parser_error( parser, b"found incompatible YAML document\0" as *const u8 as *const libc::c_char, (*token).start_mark, ); current_block = 17143798186130252483; break; } else { version_directive = yaml_malloc(size_of::() as libc::c_ulong) as *mut YamlVersionDirectiveT; (*version_directive).major = (*token).data.version_directive.major; (*version_directive).minor = (*token).data.version_directive.minor; } } else if (*token).type_ == YamlTagDirectiveToken { let value = YamlTagDirectiveT { handle: (*token).data.tag_directive.handle, prefix: (*token).data.tag_directive.prefix, }; if yaml_parser_append_tag_directive( parser, value, false, (*token).start_mark, ) .fail { current_block = 17143798186130252483; break; } PUSH!(tag_directives, value); } skip_token(parser); token = peek_token(parser); if token.is_null() { current_block = 17143798186130252483; break; } } if current_block != 17143798186130252483 { default_tag_directive = default_tag_directives.as_mut_ptr(); loop { if (*default_tag_directive).handle.is_null() { current_block = 18377268871191777778; break; } if yaml_parser_append_tag_directive( parser, *default_tag_directive, true, (*token).start_mark, ) .fail { current_block = 17143798186130252483; break; } default_tag_directive = default_tag_directive.wrapping_offset(1); } if current_block != 17143798186130252483 { if !version_directive_ref.is_null() { *version_directive_ref = version_directive; } if !tag_directives_start_ref.is_null() { if STACK_EMPTY!(tag_directives) { *tag_directives_end_ref = ptr::null_mut::(); *tag_directives_start_ref = *tag_directives_end_ref; STACK_DEL!(tag_directives); } else { *tag_directives_start_ref = tag_directives.start; *tag_directives_end_ref = tag_directives.top; } } else { STACK_DEL!(tag_directives); } if version_directive_ref.is_null() { yaml_free(version_directive as *mut libc::c_void); } return OK; } } } yaml_free(version_directive as *mut libc::c_void); while !STACK_EMPTY!(tag_directives) { let tag_directive = POP!(tag_directives); yaml_free(tag_directive.handle as *mut libc::c_void); yaml_free(tag_directive.prefix as *mut libc::c_void); } STACK_DEL!(tag_directives); FAIL } unsafe fn yaml_parser_append_tag_directive( parser: *mut YamlParserT, value: YamlTagDirectiveT, allow_duplicates: bool, mark: YamlMarkT, ) -> Success { let mut tag_directive: *mut YamlTagDirectiveT; let mut copy = YamlTagDirectiveT { handle: ptr::null_mut::(), prefix: ptr::null_mut::(), }; tag_directive = (*parser).tag_directives.start; while tag_directive != (*parser).tag_directives.top { if strcmp( value.handle as *mut libc::c_char, (*tag_directive).handle as *mut libc::c_char, ) == 0 { if allow_duplicates { return OK; } yaml_parser_set_parser_error( parser, b"found duplicate %TAG directive\0" as *const u8 as *const libc::c_char, mark, ); return FAIL; } tag_directive = tag_directive.wrapping_offset(1); } copy.handle = yaml_strdup(value.handle); copy.prefix = yaml_strdup(value.prefix); PUSH!((*parser).tag_directives, copy); OK } libyml-0.0.5/src/reader.rs000064400000000000000000000505241046102023000135230ustar 00000000000000use crate::externs::{memcmp, memmove}; use crate::ops::ForceAdd as _; use crate::success::{Success, FAIL, OK}; use crate::yaml::{size_t, yaml_char_t}; use crate::{ libc, PointerExt, YamlAnyEncoding, YamlParserT, YamlReaderError, YamlUtf16beEncoding, YamlUtf16leEncoding, YamlUtf8Encoding, }; use core::ptr::addr_of_mut; unsafe fn yaml_parser_set_reader_error( parser: *mut YamlParserT, problem: *const libc::c_char, offset: size_t, value: libc::c_int, ) -> Success { (*parser).error = YamlReaderError; let fresh0 = addr_of_mut!((*parser).problem); *fresh0 = problem; (*parser).problem_offset = offset; (*parser).problem_value = value; FAIL } const BOM_UTF8: *const libc::c_char = b"\xEF\xBB\xBF\0" as *const u8 as *const libc::c_char; const BOM_UTF16LE: *const libc::c_char = b"\xFF\xFE\0" as *const u8 as *const libc::c_char; const BOM_UTF16BE: *const libc::c_char = b"\xFE\xFF\0" as *const u8 as *const libc::c_char; unsafe fn yaml_parser_determine_encoding( parser: *mut YamlParserT, ) -> Success { while !(*parser).eof && ((*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as libc::c_long) < 3_i64 { if yaml_parser_update_raw_buffer(parser).fail { return FAIL; } } if (*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as libc::c_long >= 2_i64 && memcmp( (*parser).raw_buffer.pointer as *const libc::c_void, BOM_UTF16LE as *const libc::c_void, 2_u64, ) == 0 { (*parser).encoding = YamlUtf16leEncoding; let fresh1 = addr_of_mut!((*parser).raw_buffer.pointer); *fresh1 = (*fresh1).wrapping_offset(2_isize); let fresh2 = addr_of_mut!((*parser).offset); *fresh2 = (*fresh2).force_add(3_u64); } else if (*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as libc::c_long >= 2_i64 && memcmp( (*parser).raw_buffer.pointer as *const libc::c_void, BOM_UTF16BE as *const libc::c_void, 2_u64, ) == 0 { (*parser).encoding = YamlUtf16beEncoding; let fresh3 = addr_of_mut!((*parser).raw_buffer.pointer); *fresh3 = (*fresh3).wrapping_offset(2_isize); let fresh4 = addr_of_mut!((*parser).offset); *fresh4 = (*fresh4).force_add(3_u64); } else if (*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as libc::c_long >= 3_i64 && memcmp( (*parser).raw_buffer.pointer as *const libc::c_void, BOM_UTF8 as *const libc::c_void, 3_u64, ) == 0 { (*parser).encoding = YamlUtf8Encoding; let fresh5 = addr_of_mut!((*parser).raw_buffer.pointer); *fresh5 = (*fresh5).wrapping_offset(3_isize); let fresh6 = addr_of_mut!((*parser).offset); *fresh6 = (*fresh6).force_add(3_u64); } else { (*parser).encoding = YamlUtf8Encoding; } OK } unsafe fn yaml_parser_update_raw_buffer( parser: *mut YamlParserT, ) -> Success { let mut size_read: size_t = 0_u64; if (*parser).raw_buffer.start == (*parser).raw_buffer.pointer && (*parser).raw_buffer.last == (*parser).raw_buffer.end { return OK; } if (*parser).eof { return OK; } if (*parser).raw_buffer.start < (*parser).raw_buffer.pointer && (*parser).raw_buffer.pointer < (*parser).raw_buffer.last { let _ = memmove( (*parser).raw_buffer.start as *mut libc::c_void, (*parser).raw_buffer.pointer as *const libc::c_void, (*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as libc::c_long as libc::c_ulong, ); } let fresh7 = addr_of_mut!((*parser).raw_buffer.last); *fresh7 = (*fresh7).wrapping_offset( -((*parser) .raw_buffer .pointer .c_offset_from((*parser).raw_buffer.start) as libc::c_long as isize), ); let fresh8 = addr_of_mut!((*parser).raw_buffer.pointer); *fresh8 = (*parser).raw_buffer.start; if (*parser).read_handler.expect("non-null function pointer")( (*parser).read_handler_data, (*parser).raw_buffer.last, (*parser) .raw_buffer .end .c_offset_from((*parser).raw_buffer.last) as size_t, addr_of_mut!(size_read), ) == 0 { return yaml_parser_set_reader_error( parser, b"input error\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } let fresh9 = addr_of_mut!((*parser).raw_buffer.last); *fresh9 = (*fresh9).wrapping_offset(size_read as isize); if size_read == 0 { (*parser).eof = true; } OK } pub(crate) unsafe fn yaml_parser_update_buffer( parser: *mut YamlParserT, length: size_t, ) -> Success { let mut first = true; __assert!(((*parser).read_handler).is_some()); if (*parser).eof && (*parser).raw_buffer.pointer == (*parser).raw_buffer.last { return OK; } if (*parser).unread >= length { return OK; } if (*parser).encoding == YamlAnyEncoding && yaml_parser_determine_encoding(parser).fail { return FAIL; } if (*parser).buffer.start < (*parser).buffer.pointer && (*parser).buffer.pointer < (*parser).buffer.last { let size: size_t = (*parser) .buffer .last .c_offset_from((*parser).buffer.pointer) as size_t; let _ = memmove( (*parser).buffer.start as *mut libc::c_void, (*parser).buffer.pointer as *const libc::c_void, size, ); let fresh10 = addr_of_mut!((*parser).buffer.pointer); *fresh10 = (*parser).buffer.start; let fresh11 = addr_of_mut!((*parser).buffer.last); *fresh11 = (*parser).buffer.start.wrapping_offset(size as isize); } else if (*parser).buffer.pointer == (*parser).buffer.last { let fresh12 = addr_of_mut!((*parser).buffer.pointer); *fresh12 = (*parser).buffer.start; let fresh13 = addr_of_mut!((*parser).buffer.last); *fresh13 = (*parser).buffer.start; } while (*parser).unread < length { if (!first || (*parser).raw_buffer.pointer == (*parser).raw_buffer.last) && yaml_parser_update_raw_buffer(parser).fail { return FAIL; } first = false; while (*parser).raw_buffer.pointer != (*parser).raw_buffer.last { let mut value: libc::c_uint = 0; let value2: libc::c_uint; let mut incomplete = false; let mut octet: libc::c_uchar; let mut width: libc::c_uint = 0; let low: libc::c_int; let high: libc::c_int; let mut k: size_t; let raw_unread: size_t = (*parser) .raw_buffer .last .c_offset_from((*parser).raw_buffer.pointer) as size_t; match (*parser).encoding { YamlUtf8Encoding => { octet = *(*parser).raw_buffer.pointer; width = if octet & 0x80 == 0 { 1 } else if octet & 0xE0 == 0xC0 { 2 } else if octet & 0xF0 == 0xE0 { 3 } else if octet & 0xF8 == 0xF0 { 4 } else { 0 } as libc::c_uint; if width == 0 { return yaml_parser_set_reader_error( parser, b"invalid leading UTF-8 octet\0" as *const u8 as *const libc::c_char, (*parser).offset, octet as libc::c_int, ); } if width as libc::c_ulong > raw_unread { if (*parser).eof { return yaml_parser_set_reader_error( parser, b"incomplete UTF-8 octet sequence\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } incomplete = true; } else { value = if octet & 0x80 == 0 { octet & 0x7F } else if octet & 0xE0 == 0xC0 { octet & 0x1F } else if octet & 0xF0 == 0xE0 { octet & 0xF } else if octet & 0xF8 == 0xF0 { octet & 0x7 } else { 0 } as libc::c_uint; k = 1_u64; while k < width as libc::c_ulong { octet = *(*parser) .raw_buffer .pointer .wrapping_offset(k as isize); if octet & 0xC0 != 0x80 { return yaml_parser_set_reader_error( parser, b"invalid trailing UTF-8 octet\0" as *const u8 as *const libc::c_char, (*parser).offset.force_add(k), octet as libc::c_int, ); } value = (value << 6).force_add( (octet & 0x3F) as libc::c_uint, ); k = k.force_add(1); } if !(width == 1 || width == 2 && value >= 0x80 || width == 3 && value >= 0x800 || width == 4 && value >= 0x10000) { return yaml_parser_set_reader_error( parser, b"invalid length of a UTF-8 sequence\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } if (0xD800..=0xDFFF).contains(&value) || value > 0x10FFFF { return yaml_parser_set_reader_error( parser, b"invalid Unicode character\0" as *const u8 as *const libc::c_char, (*parser).offset, value as libc::c_int, ); } } } YamlUtf16leEncoding | YamlUtf16beEncoding => { low = if (*parser).encoding == YamlUtf16leEncoding { 0 } else { 1 }; high = if (*parser).encoding == YamlUtf16leEncoding { 1 } else { 0 }; if raw_unread < 2_u64 { if (*parser).eof { return yaml_parser_set_reader_error( parser, b"incomplete UTF-16 character\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } incomplete = true; } else { value = (*(*parser) .raw_buffer .pointer .wrapping_offset(low as isize) as libc::c_int + ((*(*parser) .raw_buffer .pointer .wrapping_offset(high as isize) as libc::c_int) << 8)) as libc::c_uint; if value & 0xFC00 == 0xDC00 { return yaml_parser_set_reader_error( parser, b"unexpected low surrogate area\0" as *const u8 as *const libc::c_char, (*parser).offset, value as libc::c_int, ); } if value & 0xFC00 == 0xD800 { width = 4; if raw_unread < 4_u64 { if (*parser).eof { return yaml_parser_set_reader_error( parser, b"incomplete UTF-16 surrogate pair\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } incomplete = true; } else { value2 = (*(*parser) .raw_buffer .pointer .wrapping_offset((low + 2) as isize) as libc::c_int + ((*(*parser) .raw_buffer .pointer .wrapping_offset( (high + 2) as isize, ) as libc::c_int) << 8)) as libc::c_uint; if value2 & 0xFC00 != 0xDC00 { return yaml_parser_set_reader_error( parser, b"expected low surrogate area\0" as *const u8 as *const libc::c_char, (*parser).offset.force_add(2_u64), value2 as libc::c_int, ); } value = 0x10000_u32 .force_add((value & 0x3FF) << 10) .force_add(value2 & 0x3FF); } } else { width = 2; } } } _ => {} } if incomplete { break; } if !(value == 0x9 || value == 0xA || value == 0xD || (0x20..=0x7E).contains(&value) || value == 0x85 || (0xA0..=0xD7FF).contains(&value) || (0xE000..=0xFFFD).contains(&value) || (0x10000..=0x10FFFF).contains(&value)) { return yaml_parser_set_reader_error( parser, b"control characters are not allowed\0" as *const u8 as *const libc::c_char, (*parser).offset, value as libc::c_int, ); } let fresh14 = addr_of_mut!((*parser).raw_buffer.pointer); *fresh14 = (*fresh14).wrapping_offset(width as isize); let fresh15 = addr_of_mut!((*parser).offset); *fresh15 = (*fresh15).force_add(width as size_t); if value <= 0x7F { let fresh16 = addr_of_mut!((*parser).buffer.last); let fresh17 = *fresh16; *fresh16 = (*fresh16).wrapping_offset(1); *fresh17 = value as yaml_char_t; } else if value <= 0x7FF { let fresh18 = addr_of_mut!((*parser).buffer.last); let fresh19 = *fresh18; *fresh18 = (*fresh18).wrapping_offset(1); *fresh19 = 0xC0_u32.force_add(value >> 6) as yaml_char_t; let fresh20 = addr_of_mut!((*parser).buffer.last); let fresh21 = *fresh20; *fresh20 = (*fresh20).wrapping_offset(1); *fresh21 = 0x80_u32.force_add(value & 0x3F) as yaml_char_t; } else if value <= 0xFFFF { let fresh22 = addr_of_mut!((*parser).buffer.last); let fresh23 = *fresh22; *fresh22 = (*fresh22).wrapping_offset(1); *fresh23 = 0xE0_u32.force_add(value >> 12) as yaml_char_t; let fresh24 = addr_of_mut!((*parser).buffer.last); let fresh25 = *fresh24; *fresh24 = (*fresh24).wrapping_offset(1); *fresh25 = 0x80_u32.force_add(value >> 6 & 0x3F) as yaml_char_t; let fresh26 = addr_of_mut!((*parser).buffer.last); let fresh27 = *fresh26; *fresh26 = (*fresh26).wrapping_offset(1); *fresh27 = 0x80_u32.force_add(value & 0x3F) as yaml_char_t; } else { let fresh28 = addr_of_mut!((*parser).buffer.last); let fresh29 = *fresh28; *fresh28 = (*fresh28).wrapping_offset(1); *fresh29 = 0xF0_u32.force_add(value >> 18) as yaml_char_t; let fresh30 = addr_of_mut!((*parser).buffer.last); let fresh31 = *fresh30; *fresh30 = (*fresh30).wrapping_offset(1); *fresh31 = 0x80_u32.force_add(value >> 12 & 0x3F) as yaml_char_t; let fresh32 = addr_of_mut!((*parser).buffer.last); let fresh33 = *fresh32; *fresh32 = (*fresh32).wrapping_offset(1); *fresh33 = 0x80_u32.force_add(value >> 6 & 0x3F) as yaml_char_t; let fresh34 = addr_of_mut!((*parser).buffer.last); let fresh35 = *fresh34; *fresh34 = (*fresh34).wrapping_offset(1); *fresh35 = 0x80_u32.force_add(value & 0x3F) as yaml_char_t; } let fresh36 = addr_of_mut!((*parser).unread); *fresh36 = (*fresh36).force_add(1); } if (*parser).eof { let fresh37 = addr_of_mut!((*parser).buffer.last); let fresh38 = *fresh37; *fresh37 = (*fresh37).wrapping_offset(1); *fresh38 = b'\0'; let fresh39 = addr_of_mut!((*parser).unread); *fresh39 = (*fresh39).force_add(1); return OK; } } if (*parser).offset >= (!0_u64).wrapping_div(2_u64) { return yaml_parser_set_reader_error( parser, b"input is too long\0" as *const u8 as *const libc::c_char, (*parser).offset, -1, ); } OK } libyml-0.0.5/src/scanner.rs000064400000000000000000003347751046102023000137270ustar 00000000000000use crate::externs::{memcpy, memmove, memset, strcmp, strlen}; use crate::internal::{yaml_queue_extend, yaml_stack_extend}; use crate::memory::yaml_free; use crate::memory::yaml_malloc; use crate::ops::{ForceAdd as _, ForceMul as _}; use crate::reader::yaml_parser_update_buffer; use crate::string::{yaml_string_extend, yaml_string_join}; use crate::success::{Success, FAIL, OK}; use crate::yaml::{ ptrdiff_t, size_t, yaml_char_t, YamlStringT, NULL_STRING, }; use crate::{ libc, PointerExt, YamlAliasToken, YamlAnchorToken, YamlBlockEndToken, YamlBlockEntryToken, YamlBlockMappingStartToken, YamlBlockSequenceStartToken, YamlDocumentEndToken, YamlDocumentStartToken, YamlDoubleQuotedScalarStyle, YamlFlowEntryToken, YamlFlowMappingEndToken, YamlFlowMappingStartToken, YamlFlowSequenceEndToken, YamlFlowSequenceStartToken, YamlFoldedScalarStyle, YamlKeyToken, YamlLiteralScalarStyle, YamlMarkT, YamlMemoryError, YamlNoError, YamlParserT, YamlPlainScalarStyle, YamlScalarToken, YamlScannerError, YamlSimpleKeyT, YamlSingleQuotedScalarStyle, YamlStreamEndToken, YamlStreamStartToken, YamlTagDirectiveToken, YamlTagToken, YamlTokenT, YamlTokenTypeT, YamlValueToken, YamlVersionDirectiveToken, }; use core::mem::{size_of, MaybeUninit}; use core::ptr::{self, addr_of_mut}; unsafe fn cache(parser: *mut YamlParserT, length: size_t) -> Success { if (*parser).unread >= length { OK } else { yaml_parser_update_buffer(parser, length) } } unsafe fn skip(parser: *mut YamlParserT) { let width = WIDTH!((*parser).buffer); (*parser).mark.index = (*parser).mark.index.force_add(width as u64); (*parser).mark.column = (*parser).mark.column.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(width as isize); } unsafe fn skip_line(parser: *mut YamlParserT) { if IS_CRLF!((*parser).buffer) { (*parser).mark.index = (*parser).mark.index.force_add(2); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(2); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(2); } else if IS_BREAK!((*parser).buffer) { let width = WIDTH!((*parser).buffer); (*parser).mark.index = (*parser).mark.index.force_add(width as u64); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(width as isize); }; } unsafe fn read(parser: *mut YamlParserT, string: *mut YamlStringT) { STRING_EXTEND!(*string); let width = WIDTH!((*parser).buffer); copy!(*string, (*parser).buffer); (*parser).mark.index = (*parser).mark.index.force_add(width as u64); (*parser).mark.column = (*parser).mark.column.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); } unsafe fn read_line( parser: *mut YamlParserT, string: *mut YamlStringT, ) { STRING_EXTEND!(*string); if CHECK_AT!((*parser).buffer, b'\r', 0) && CHECK_AT!((*parser).buffer, b'\n', 1) { *(*string).pointer = b'\n'; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(2); (*parser).mark.index = (*parser).mark.index.force_add(2); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(2); } else if CHECK_AT!((*parser).buffer, b'\r', 0) || CHECK_AT!((*parser).buffer, b'\n', 0) { *(*string).pointer = b'\n'; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(1); (*parser).mark.index = (*parser).mark.index.force_add(1); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); } else if CHECK_AT!((*parser).buffer, b'\xC2', 0) && CHECK_AT!((*parser).buffer, b'\x85', 1) { *(*string).pointer = b'\n'; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(2); (*parser).mark.index = (*parser).mark.index.force_add(2); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); } else if CHECK_AT!((*parser).buffer, b'\xE2', 0) && CHECK_AT!((*parser).buffer, b'\x80', 1) && (CHECK_AT!((*parser).buffer, b'\xA8', 2) || CHECK_AT!((*parser).buffer, b'\xA9', 2)) { *(*string).pointer = *(*parser).buffer.pointer; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(1); *(*string).pointer = *(*parser).buffer.pointer; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(1); *(*string).pointer = *(*parser).buffer.pointer; (*string).pointer = (*string).pointer.wrapping_offset(1); (*parser).buffer.pointer = (*parser).buffer.pointer.wrapping_offset(1); (*parser).mark.index = (*parser).mark.index.force_add(3); (*parser).mark.column = 0; (*parser).mark.line = (*parser).mark.line.force_add(1); (*parser).unread = (*parser).unread.wrapping_sub(1); }; } macro_rules! read { ($parser:expr, $string:expr) => { read($parser, addr_of_mut!($string)) }; } macro_rules! read_line { ($parser:expr, $string:expr) => { read_line($parser, addr_of_mut!($string)) }; } /// Scan the input stream and produce the next token. /// /// Call the function subsequently to produce a sequence of tokens corresponding /// to the input stream. The initial token has the type YamlStreamStartToken /// while the ending token has the type YamlStreamEndToken. /// /// An application is responsible for freeing any buffers associated with the /// produced token object using the yaml_token_delete function. /// /// An application must not alternate the calls of yaml_parser_scan() with the /// calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break /// the parser. /// /// # Safety /// /// - The `parser` and `token` pointers must be valid and non-null. /// - The `parser` must be properly initialized and not already in an error state. /// - The `token` must be properly allocated and have enough capacity to store the /// produced token. /// - The function should not be called alternately with `yaml_parser_parse()` or /// `yaml_parser_load()`, as it may break the parser state. /// - The caller is responsible for freeing any buffers associated with the produced /// token using the `yaml_token_delete` function. /// pub unsafe fn yaml_parser_scan( parser: *mut YamlParserT, token: *mut YamlTokenT, ) -> Success { __assert!(!parser.is_null()); __assert!(!token.is_null()); let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); if (*parser).stream_end_produced || (*parser).error != YamlNoError { return OK; } if !(*parser).token_available && yaml_parser_fetch_more_tokens(parser).fail { return FAIL; } *token = DEQUEUE!((*parser).tokens); (*parser).token_available = false; let fresh2 = addr_of_mut!((*parser).tokens_parsed); *fresh2 = (*fresh2).force_add(1); if (*token).type_ == YamlStreamEndToken { (*parser).stream_end_produced = true; } OK } unsafe fn yaml_parser_set_scanner_error( parser: *mut YamlParserT, context: *const libc::c_char, context_mark: YamlMarkT, problem: *const libc::c_char, ) { (*parser).error = YamlScannerError; let fresh3 = addr_of_mut!((*parser).context); *fresh3 = context; (*parser).context_mark = context_mark; let fresh4 = addr_of_mut!((*parser).problem); *fresh4 = problem; (*parser).problem_mark = (*parser).mark; } pub(crate) unsafe fn yaml_parser_fetch_more_tokens( parser: *mut YamlParserT, ) -> Success { let mut need_more_tokens; loop { need_more_tokens = false; if (*parser).tokens.head == (*parser).tokens.tail { need_more_tokens = true; } else { let mut simple_key: *mut YamlSimpleKeyT; if yaml_parser_stale_simple_keys(parser).fail { return FAIL; } simple_key = (*parser) .simple_keys .start .add((*parser).not_simple_keys as usize); while simple_key != (*parser).simple_keys.top { if (*simple_key).possible && (*simple_key).token_number == (*parser).tokens_parsed { need_more_tokens = true; break; } else { simple_key = simple_key.wrapping_offset(1); } } } if !need_more_tokens { break; } if yaml_parser_fetch_next_token(parser).fail { return FAIL; } } (*parser).token_available = true; OK } unsafe fn yaml_parser_fetch_next_token( parser: *mut YamlParserT, ) -> Success { if cache(parser, 1_u64).fail { return FAIL; } if !(*parser).stream_start_produced { yaml_parser_fetch_stream_start(parser); return OK; } if yaml_parser_scan_to_next_token(parser).fail { return FAIL; } if yaml_parser_stale_simple_keys(parser).fail { return FAIL; } yaml_parser_unroll_indent( parser, (*parser).mark.column as ptrdiff_t, ); if cache(parser, 4_u64).fail { return FAIL; } if IS_Z!((*parser).buffer) { return yaml_parser_fetch_stream_end(parser); } if (*parser).mark.column == 0_u64 && CHECK!((*parser).buffer, b'%') { return yaml_parser_fetch_directive(parser); } if (*parser).mark.column == 0_u64 && CHECK_AT!((*parser).buffer, b'-', 0) && CHECK_AT!((*parser).buffer, b'-', 1) && CHECK_AT!((*parser).buffer, b'-', 2) && IS_BLANKZ_AT!((*parser).buffer, 3) { return yaml_parser_fetch_document_indicator( parser, YamlDocumentStartToken, ); } if (*parser).mark.column == 0_u64 && CHECK_AT!((*parser).buffer, b'.', 0) && CHECK_AT!((*parser).buffer, b'.', 1) && CHECK_AT!((*parser).buffer, b'.', 2) && IS_BLANKZ_AT!((*parser).buffer, 3) { return yaml_parser_fetch_document_indicator( parser, YamlDocumentEndToken, ); } if CHECK!((*parser).buffer, b'[') { return yaml_parser_fetch_flow_collection_start( parser, YamlFlowSequenceStartToken, ); } if CHECK!((*parser).buffer, b'{') { return yaml_parser_fetch_flow_collection_start( parser, YamlFlowMappingStartToken, ); } if CHECK!((*parser).buffer, b']') { return yaml_parser_fetch_flow_collection_end( parser, YamlFlowSequenceEndToken, ); } if CHECK!((*parser).buffer, b'}') { return yaml_parser_fetch_flow_collection_end( parser, YamlFlowMappingEndToken, ); } if CHECK!((*parser).buffer, b',') { return yaml_parser_fetch_flow_entry(parser); } if CHECK!((*parser).buffer, b'-') && IS_BLANKZ_AT!((*parser).buffer, 1) { return yaml_parser_fetch_block_entry(parser); } if CHECK!((*parser).buffer, b'?') && ((*parser).flow_level != 0 || IS_BLANKZ_AT!((*parser).buffer, 1)) { return yaml_parser_fetch_key(parser); } if CHECK!((*parser).buffer, b':') && ((*parser).flow_level != 0 || IS_BLANKZ_AT!((*parser).buffer, 1)) { return yaml_parser_fetch_value(parser); } if CHECK!((*parser).buffer, b'*') { return yaml_parser_fetch_anchor(parser, YamlAliasToken); } if CHECK!((*parser).buffer, b'&') { return yaml_parser_fetch_anchor(parser, YamlAnchorToken); } if CHECK!((*parser).buffer, b'!') { return yaml_parser_fetch_tag(parser); } if CHECK!((*parser).buffer, b'|') && (*parser).flow_level == 0 { return yaml_parser_fetch_block_scalar(parser, true); } if CHECK!((*parser).buffer, b'>') && (*parser).flow_level == 0 { return yaml_parser_fetch_block_scalar(parser, false); } if CHECK!((*parser).buffer, b'\'') { return yaml_parser_fetch_flow_scalar(parser, true); } if CHECK!((*parser).buffer, b'"') { return yaml_parser_fetch_flow_scalar(parser, false); } if !(IS_BLANKZ!((*parser).buffer) || CHECK!((*parser).buffer, b'-') || CHECK!((*parser).buffer, b'?') || CHECK!((*parser).buffer, b':') || CHECK!((*parser).buffer, b',') || CHECK!((*parser).buffer, b'[') || CHECK!((*parser).buffer, b']') || CHECK!((*parser).buffer, b'{') || CHECK!((*parser).buffer, b'}') || CHECK!((*parser).buffer, b'#') || CHECK!((*parser).buffer, b'&') || CHECK!((*parser).buffer, b'*') || CHECK!((*parser).buffer, b'!') || CHECK!((*parser).buffer, b'|') || CHECK!((*parser).buffer, b'>') || CHECK!((*parser).buffer, b'\'') || CHECK!((*parser).buffer, b'"') || CHECK!((*parser).buffer, b'%') || CHECK!((*parser).buffer, b'@') || CHECK!((*parser).buffer, b'`')) || CHECK!((*parser).buffer, b'-') && !IS_BLANK_AT!((*parser).buffer, 1) || (*parser).flow_level == 0 && (CHECK!((*parser).buffer, b'?') || CHECK!((*parser).buffer, b':')) && !IS_BLANKZ_AT!((*parser).buffer, 1) { return yaml_parser_fetch_plain_scalar(parser); } yaml_parser_set_scanner_error( parser, b"while scanning for the next token\0" as *const u8 as *const libc::c_char, (*parser).mark, b"found character that cannot start any token\0" as *const u8 as *const libc::c_char, ); FAIL } unsafe fn yaml_parser_stale_simple_keys( parser: *mut YamlParserT, ) -> Success { let mut simple_key: *mut YamlSimpleKeyT; simple_key = (*parser) .simple_keys .start .add((*parser).not_simple_keys as usize); while simple_key != (*parser).simple_keys.top { if (*simple_key).possible && ((*simple_key).mark.line < (*parser).mark.line || (*simple_key).mark.index.force_add(1024_u64) < (*parser).mark.index) { if (*simple_key).required { yaml_parser_set_scanner_error( parser, b"while scanning a simple key\0" as *const u8 as *const libc::c_char, (*simple_key).mark, b"could not find expected ':'\0" as *const u8 as *const libc::c_char, ); return FAIL; } (*simple_key).possible = false; if (*parser) .simple_keys .start .add((*parser).not_simple_keys as usize) == simple_key { (*parser).not_simple_keys += 1; } } simple_key = simple_key.wrapping_offset(1); } OK } unsafe fn yaml_parser_save_simple_key( parser: *mut YamlParserT, ) -> Success { let required = (*parser).flow_level == 0 && (*parser).indent as libc::c_long == (*parser).mark.column as ptrdiff_t; if (*parser).simple_key_allowed { let simple_key = YamlSimpleKeyT { possible: true, required, token_number: (*parser).tokens_parsed.force_add( (*parser) .tokens .tail .c_offset_from((*parser).tokens.head) as libc::c_ulong, ), mark: (*parser).mark, }; if yaml_parser_remove_simple_key(parser).fail { return FAIL; } *(*parser).simple_keys.top.wrapping_offset(-1_isize) = simple_key; if (*parser) .simple_keys .start .add((*parser).not_simple_keys as usize) == (*parser).simple_keys.top { (*parser).not_simple_keys -= 1; } } OK } unsafe fn yaml_parser_remove_simple_key( parser: *mut YamlParserT, ) -> Success { let simple_key: *mut YamlSimpleKeyT = (*parser).simple_keys.top.wrapping_offset(-1_isize); if (*simple_key).possible && (*simple_key).required { yaml_parser_set_scanner_error( parser, b"while scanning a simple key\0" as *const u8 as *const libc::c_char, (*simple_key).mark, b"could not find expected ':'\0" as *const u8 as *const libc::c_char, ); return FAIL; } (*simple_key).possible = false; OK } unsafe fn yaml_parser_increase_flow_level( parser: *mut YamlParserT, ) -> Success { let empty_simple_key = YamlSimpleKeyT { possible: false, required: false, token_number: 0_u64, mark: YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }, }; PUSH!((*parser).simple_keys, empty_simple_key); if (*parser).flow_level == libc::c_int::MAX { (*parser).error = YamlMemoryError; return FAIL; } let fresh7 = addr_of_mut!((*parser).flow_level); *fresh7 += 1; OK } unsafe fn yaml_parser_decrease_flow_level(parser: *mut YamlParserT) { if (*parser).flow_level != 0 { let fresh8 = addr_of_mut!((*parser).flow_level); *fresh8 -= 1; if (*parser) .simple_keys .start .add((*parser).not_simple_keys as usize) == (*parser).simple_keys.top { (*parser).not_simple_keys -= 1; } let _ = POP!((*parser).simple_keys); } } unsafe fn yaml_parser_roll_indent( parser: *mut YamlParserT, column: ptrdiff_t, number: ptrdiff_t, type_: YamlTokenTypeT, mark: YamlMarkT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if (*parser).flow_level != 0 { return OK; } if ((*parser).indent as libc::c_long) < column { PUSH!((*parser).indents, (*parser).indent); if column > ptrdiff_t::from(libc::c_int::MAX) { (*parser).error = YamlMemoryError; return FAIL; } (*parser).indent = column as libc::c_int; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = type_; (*token).start_mark = mark; (*token).end_mark = mark; if number == -1_i64 { ENQUEUE!((*parser).tokens, *token); } else { QUEUE_INSERT!( (*parser).tokens, (number as libc::c_ulong) .wrapping_sub((*parser).tokens_parsed), *token ); } } OK } unsafe fn yaml_parser_unroll_indent( parser: *mut YamlParserT, column: ptrdiff_t, ) { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if (*parser).flow_level != 0 { return; } while (*parser).indent as libc::c_long > column { let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlBlockEndToken; (*token).start_mark = (*parser).mark; (*token).end_mark = (*parser).mark; ENQUEUE!((*parser).tokens, *token); (*parser).indent = POP!((*parser).indents); } } unsafe fn yaml_parser_fetch_stream_start(parser: *mut YamlParserT) { let simple_key = YamlSimpleKeyT { possible: false, required: false, token_number: 0_u64, mark: YamlMarkT { index: 0_u64, line: 0_u64, column: 0_u64, }, }; let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); (*parser).indent = -1; PUSH!((*parser).simple_keys, simple_key); (*parser).not_simple_keys = 1; (*parser).simple_key_allowed = true; (*parser).stream_start_produced = true; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlStreamStartToken; (*token).start_mark = (*parser).mark; (*token).end_mark = (*parser).mark; (*token).data.stream_start.encoding = (*parser).encoding; ENQUEUE!((*parser).tokens, *token); } unsafe fn yaml_parser_fetch_stream_end( parser: *mut YamlParserT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if (*parser).mark.column != 0_u64 { (*parser).mark.column = 0_u64; let fresh22 = addr_of_mut!((*parser).mark.line); *fresh22 = (*fresh22).force_add(1); } yaml_parser_unroll_indent(parser, -1_i64); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlStreamEndToken; (*token).start_mark = (*parser).mark; (*token).end_mark = (*parser).mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_directive( parser: *mut YamlParserT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); yaml_parser_unroll_indent(parser, -1_i64); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; if yaml_parser_scan_directive(parser, token).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_document_indicator( parser: *mut YamlParserT, type_: YamlTokenTypeT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); yaml_parser_unroll_indent(parser, -1_i64); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; let start_mark: YamlMarkT = (*parser).mark; skip(parser); skip(parser); skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = type_; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_flow_collection_start( parser: *mut YamlParserT, type_: YamlTokenTypeT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_save_simple_key(parser).fail { return FAIL; } if yaml_parser_increase_flow_level(parser).fail { return FAIL; } (*parser).simple_key_allowed = true; let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = type_; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_flow_collection_end( parser: *mut YamlParserT, type_: YamlTokenTypeT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } yaml_parser_decrease_flow_level(parser); (*parser).simple_key_allowed = false; let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = type_; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_flow_entry( parser: *mut YamlParserT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = true; let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlFlowEntryToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_block_entry( parser: *mut YamlParserT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if (*parser).flow_level == 0 { if !(*parser).simple_key_allowed { yaml_parser_set_scanner_error( parser, ptr::null::(), (*parser).mark, b"block sequence entries are not allowed in this context\0" as *const u8 as *const libc::c_char, ); return FAIL; } if yaml_parser_roll_indent( parser, (*parser).mark.column as ptrdiff_t, -1_i64, YamlBlockSequenceStartToken, (*parser).mark, ) .fail { return FAIL; } } if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = true; let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlBlockEntryToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_key(parser: *mut YamlParserT) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if (*parser).flow_level == 0 { if !(*parser).simple_key_allowed { yaml_parser_set_scanner_error( parser, ptr::null::(), (*parser).mark, b"mapping keys are not allowed in this context\0" as *const u8 as *const libc::c_char, ); return FAIL; } if yaml_parser_roll_indent( parser, (*parser).mark.column as ptrdiff_t, -1_i64, YamlBlockMappingStartToken, (*parser).mark, ) .fail { return FAIL; } } if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = (*parser).flow_level == 0; let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlKeyToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_value(parser: *mut YamlParserT) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); let simple_key: *mut YamlSimpleKeyT = (*parser).simple_keys.top.wrapping_offset(-1_isize); if (*simple_key).possible { let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlKeyToken; (*token).start_mark = (*simple_key).mark; (*token).end_mark = (*simple_key).mark; QUEUE_INSERT!( (*parser).tokens, ((*simple_key).token_number) .wrapping_sub((*parser).tokens_parsed), *token ); if yaml_parser_roll_indent( parser, (*simple_key).mark.column as ptrdiff_t, (*simple_key).token_number as ptrdiff_t, YamlBlockMappingStartToken, (*simple_key).mark, ) .fail { return FAIL; } (*simple_key).possible = false; (*parser).simple_key_allowed = false; } else { if (*parser).flow_level == 0 { if !(*parser).simple_key_allowed { yaml_parser_set_scanner_error( parser, ptr::null::(), (*parser).mark, b"mapping values are not allowed in this context\0" as *const u8 as *const libc::c_char, ); return FAIL; } if yaml_parser_roll_indent( parser, (*parser).mark.column as ptrdiff_t, -1_i64, YamlBlockMappingStartToken, (*parser).mark, ) .fail { return FAIL; } } (*parser).simple_key_allowed = (*parser).flow_level == 0; } let start_mark: YamlMarkT = (*parser).mark; skip(parser); let end_mark: YamlMarkT = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlValueToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_anchor( parser: *mut YamlParserT, type_: YamlTokenTypeT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_save_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; if yaml_parser_scan_anchor(parser, token, type_).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_tag(parser: *mut YamlParserT) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_save_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; if yaml_parser_scan_tag(parser, token).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_block_scalar( parser: *mut YamlParserT, literal: bool, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_remove_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = true; if yaml_parser_scan_block_scalar(parser, token, literal).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_flow_scalar( parser: *mut YamlParserT, single: bool, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_save_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; if yaml_parser_scan_flow_scalar(parser, token, single).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_fetch_plain_scalar( parser: *mut YamlParserT, ) -> Success { let mut token = MaybeUninit::::uninit(); let token = token.as_mut_ptr(); if yaml_parser_save_simple_key(parser).fail { return FAIL; } (*parser).simple_key_allowed = false; if yaml_parser_scan_plain_scalar(parser, token).fail { return FAIL; } ENQUEUE!((*parser).tokens, *token); OK } unsafe fn yaml_parser_scan_to_next_token( parser: *mut YamlParserT, ) -> Success { loop { if cache(parser, 1_u64).fail { return FAIL; } if (*parser).mark.column == 0_u64 && IS_BOM!((*parser).buffer) { skip(parser); } if cache(parser, 1_u64).fail { return FAIL; } let mut should_continue = true; while should_continue { if CHECK!((*parser).buffer, b' ') || ((*parser).flow_level != 0 || !(*parser).simple_key_allowed) && CHECK!((*parser).buffer, b'\t') { skip(parser); if cache(parser, 1_u64).fail { return FAIL; } } else { should_continue = false; } } if CHECK!((*parser).buffer, b'#') { while !IS_BREAKZ!((*parser).buffer) { skip(parser); if cache(parser, 1_u64).fail { return FAIL; } } } if !IS_BREAK!((*parser).buffer) { break; } if cache(parser, 2_u64).fail { return FAIL; } skip_line(parser); if (*parser).flow_level == 0 { (*parser).simple_key_allowed = true; } } OK } unsafe fn yaml_parser_scan_directive( parser: *mut YamlParserT, token: *mut YamlTokenT, ) -> Success { let mut current_block: u64; let end_mark: YamlMarkT; let mut name: *mut yaml_char_t = ptr::null_mut::(); let mut major: libc::c_int = 0; let mut minor: libc::c_int = 0; let mut handle: *mut yaml_char_t = ptr::null_mut::(); let mut prefix: *mut yaml_char_t = ptr::null_mut::(); let start_mark: YamlMarkT = (*parser).mark; skip(parser); if yaml_parser_scan_directive_name( parser, start_mark, addr_of_mut!(name), ) .ok { if strcmp( name as *mut libc::c_char, b"YAML\0" as *const u8 as *const libc::c_char, ) == 0 { if yaml_parser_scan_version_directive_value( parser, start_mark, addr_of_mut!(major), addr_of_mut!(minor), ) .fail { current_block = 11397968426844348457; } else { end_mark = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlVersionDirectiveToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; (*token).data.version_directive.major = major; (*token).data.version_directive.minor = minor; current_block = 17407779659766490442; } } else if strcmp( name as *mut libc::c_char, b"TAG\0" as *const u8 as *const libc::c_char, ) == 0 { if yaml_parser_scan_tag_directive_value( parser, start_mark, addr_of_mut!(handle), addr_of_mut!(prefix), ) .fail { current_block = 11397968426844348457; } else { end_mark = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlTagDirectiveToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh112 = addr_of_mut!((*token).data.tag_directive.handle); *fresh112 = handle; let fresh113 = addr_of_mut!((*token).data.tag_directive.prefix); *fresh113 = prefix; current_block = 17407779659766490442; } } else { yaml_parser_set_scanner_error( parser, b"while scanning a directive\0" as *const u8 as *const libc::c_char, start_mark, b"found unknown directive name\0" as *const u8 as *const libc::c_char, ); current_block = 11397968426844348457; } if current_block != 11397968426844348457 && cache(parser, 1_u64).ok { loop { if !IS_BLANK!((*parser).buffer) { current_block = 11584701595673473500; break; } skip(parser); if cache(parser, 1_u64).fail { current_block = 11397968426844348457; break; } } if current_block != 11397968426844348457 { if CHECK!((*parser).buffer, b'#') { loop { if IS_BREAKZ!((*parser).buffer) { current_block = 6669252993407410313; break; } skip(parser); if cache(parser, 1_u64).fail { current_block = 11397968426844348457; break; } } } else { current_block = 6669252993407410313; } if current_block != 11397968426844348457 { if !IS_BREAKZ!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected comment or line break\0" as *const u8 as *const libc::c_char, ); } else { if IS_BREAK!((*parser).buffer) { if cache(parser, 2_u64).fail { current_block = 11397968426844348457; } else { skip_line(parser); current_block = 652864300344834934; } } else { current_block = 652864300344834934; } if current_block != 11397968426844348457 { yaml_free(name as *mut libc::c_void); return OK; } } } } } } yaml_free(prefix as *mut libc::c_void); yaml_free(handle as *mut libc::c_void); yaml_free(name as *mut libc::c_void); FAIL } unsafe fn yaml_parser_scan_directive_name( parser: *mut YamlParserT, start_mark: YamlMarkT, name: *mut *mut yaml_char_t, ) -> Success { let current_block: u64; let mut string = NULL_STRING; STRING_INIT!(string); if cache(parser, 1_u64).ok { loop { if !IS_ALPHA!((*parser).buffer) { current_block = 10879442775620481940; break; } read!(parser, string); if cache(parser, 1_u64).fail { current_block = 8318012024179131575; break; } } if current_block != 8318012024179131575 { if string.start == string.pointer { yaml_parser_set_scanner_error( parser, b"while scanning a directive\0" as *const u8 as *const libc::c_char, start_mark, b"could not find expected directive name\0" as *const u8 as *const libc::c_char, ); } else if !IS_BLANKZ!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a directive\0" as *const u8 as *const libc::c_char, start_mark, b"found unexpected non-alphabetical character\0" as *const u8 as *const libc::c_char, ); } else { *name = string.start; return OK; } } } STRING_DEL!(string); FAIL } unsafe fn yaml_parser_scan_version_directive_value( parser: *mut YamlParserT, start_mark: YamlMarkT, major: *mut libc::c_int, minor: *mut libc::c_int, ) -> Success { if cache(parser, 1_u64).fail { return FAIL; } while IS_BLANK!((*parser).buffer) { skip(parser); if cache(parser, 1_u64).fail { return FAIL; } } if yaml_parser_scan_version_directive_number( parser, start_mark, major, ) .fail { return FAIL; } if !CHECK!((*parser).buffer, b'.') { yaml_parser_set_scanner_error( parser, b"while scanning a %YAML directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected digit or '.' character\0" as *const u8 as *const libc::c_char, ); return FAIL; } skip(parser); yaml_parser_scan_version_directive_number(parser, start_mark, minor) } const MAX_NUMBER_LENGTH: u64 = 9_u64; unsafe fn yaml_parser_scan_version_directive_number( parser: *mut YamlParserT, start_mark: YamlMarkT, number: *mut libc::c_int, ) -> Success { let mut value: libc::c_int = 0; let mut length: size_t = 0_u64; if cache(parser, 1_u64).fail { return FAIL; } while !(*parser).buffer.is_empty() && IS_DIGIT!((*parser).buffer) { length = length.force_add(1); if length > MAX_NUMBER_LENGTH { yaml_parser_set_scanner_error( parser, b"while scanning a %YAML directive\0" as *const u8 as *const libc::c_char, start_mark, b"found extremely long version number\0" as *const u8 as *const libc::c_char, ); return FAIL; } value = value.force_mul(10).force_add(AS_DIGIT!((*parser).buffer)); (*parser).buffer.next(); if cache(parser, 1_u64).fail { return FAIL; } } if length == 0 { yaml_parser_set_scanner_error( parser, b"while scanning a %YAML directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected version number\0" as *const u8 as *const libc::c_char, ); return FAIL; } *number = value; OK } unsafe fn yaml_parser_scan_tag_directive_value( parser: *mut YamlParserT, start_mark: YamlMarkT, handle: *mut *mut yaml_char_t, prefix: *mut *mut yaml_char_t, ) -> Success { let mut current_block: u64; let mut handle_value: *mut yaml_char_t = ptr::null_mut::(); let mut prefix_value: *mut yaml_char_t = ptr::null_mut::(); if cache(parser, 1_u64).fail { current_block = 5231181710497607163; } else { current_block = 14916268686031723178; } 'c_34337: loop { match current_block { 5231181710497607163 => { yaml_free(handle_value as *mut libc::c_void); yaml_free(prefix_value as *mut libc::c_void); return FAIL; } _ => { if IS_BLANK!((*parser).buffer) { skip(parser); if cache(parser, 1_u64).fail { current_block = 5231181710497607163; } else { current_block = 14916268686031723178; } } else { if yaml_parser_scan_tag_handle( parser, true, start_mark, addr_of_mut!(handle_value), ) .fail { current_block = 5231181710497607163; continue; } if cache(parser, 1_u64).fail { current_block = 5231181710497607163; continue; } if !IS_BLANK!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a %TAG directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected whitespace\0" as *const u8 as *const libc::c_char, ); current_block = 5231181710497607163; } else { while IS_BLANK!((*parser).buffer) { skip(parser); if cache(parser, 1_u64).fail { current_block = 5231181710497607163; continue 'c_34337; } } if yaml_parser_scan_tag_uri( parser, true, true, ptr::null_mut::(), start_mark, addr_of_mut!(prefix_value), ) .fail { current_block = 5231181710497607163; continue; } if cache(parser, 1_u64).fail { current_block = 5231181710497607163; continue; } if !IS_BLANKZ!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a %TAG directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected whitespace or line break\0" as *const u8 as *const libc::c_char, ); current_block = 5231181710497607163; } else { *handle = handle_value; *prefix = prefix_value; return OK; } } } } } } } unsafe fn yaml_parser_scan_anchor( parser: *mut YamlParserT, token: *mut YamlTokenT, type_: YamlTokenTypeT, ) -> Success { let current_block: u64; let mut length: libc::c_int = 0; let end_mark: YamlMarkT; let mut string = NULL_STRING; STRING_INIT!(string); let start_mark: YamlMarkT = (*parser).mark; skip(parser); if cache(parser, 1_u64).ok { loop { if !IS_ALPHA!((*parser).buffer) { current_block = 2868539653012386629; break; } read!(parser, string); if cache(parser, 1_u64).fail { current_block = 5883759901342942623; break; } length += 1; } if current_block != 5883759901342942623 { end_mark = (*parser).mark; if length == 0 || !(IS_BLANKZ!((*parser).buffer) || CHECK!((*parser).buffer, b'?') || CHECK!((*parser).buffer, b':') || CHECK!((*parser).buffer, b',') || CHECK!((*parser).buffer, b']') || CHECK!((*parser).buffer, b'}') || CHECK!((*parser).buffer, b'%') || CHECK!((*parser).buffer, b'@') || CHECK!((*parser).buffer, b'`')) { yaml_parser_set_scanner_error( parser, if type_ == YamlAnchorToken { b"while scanning an anchor\0" as *const u8 as *const libc::c_char } else { b"while scanning an alias\0" as *const u8 as *const libc::c_char }, start_mark, b"did not find expected alphabetic or numeric character\0" as *const u8 as *const libc::c_char, ); } else { if type_ == YamlAnchorToken { let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlAnchorToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh220 = addr_of_mut!((*token).data.anchor.value); *fresh220 = string.start; } else { let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlAliasToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh221 = addr_of_mut!((*token).data.alias.value); *fresh221 = string.start; } return OK; } } } STRING_DEL!(string); FAIL } unsafe fn yaml_parser_scan_tag( parser: *mut YamlParserT, token: *mut YamlTokenT, ) -> Success { let mut current_block: u64; let mut handle: *mut yaml_char_t = ptr::null_mut::(); let mut suffix: *mut yaml_char_t = ptr::null_mut::(); let end_mark: YamlMarkT; let start_mark: YamlMarkT = (*parser).mark; if cache(parser, 2_u64).ok { if CHECK_AT!((*parser).buffer, b'<', 1) { handle = yaml_malloc(1_u64) as *mut yaml_char_t; *handle = b'\0'; skip(parser); skip(parser); if yaml_parser_scan_tag_uri( parser, true, false, ptr::null_mut::(), start_mark, addr_of_mut!(suffix), ) .fail { current_block = 17708497480799081542; } else if !CHECK!((*parser).buffer, b'>') { yaml_parser_set_scanner_error( parser, b"while scanning a tag\0" as *const u8 as *const libc::c_char, start_mark, b"did not find the expected '>'\0" as *const u8 as *const libc::c_char, ); current_block = 17708497480799081542; } else { skip(parser); current_block = 4488286894823169796; } } else if yaml_parser_scan_tag_handle( parser, false, start_mark, addr_of_mut!(handle), ) .fail { current_block = 17708497480799081542; } else if *handle == b'!' && *handle.wrapping_offset(1_isize) != b'\0' && *handle.wrapping_offset( strlen(handle as *mut libc::c_char).wrapping_sub(1_u64) as isize, ) == b'!' { if yaml_parser_scan_tag_uri( parser, false, false, ptr::null_mut::(), start_mark, addr_of_mut!(suffix), ) .fail { current_block = 17708497480799081542; } else { current_block = 4488286894823169796; } } else if yaml_parser_scan_tag_uri( parser, false, false, handle, start_mark, addr_of_mut!(suffix), ) .fail { current_block = 17708497480799081542; } else { yaml_free(handle as *mut libc::c_void); handle = yaml_malloc(2_u64) as *mut yaml_char_t; *handle = b'!'; *handle.wrapping_offset(1_isize) = b'\0'; if *suffix == b'\0' { core::mem::swap(&mut handle, &mut suffix); } current_block = 4488286894823169796; } if current_block != 17708497480799081542 && cache(parser, 1_u64).ok { if !IS_BLANKZ!((*parser).buffer) { if (*parser).flow_level == 0 || !CHECK!((*parser).buffer, b',') { yaml_parser_set_scanner_error( parser, b"while scanning a tag\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected whitespace or line break\0" as *const u8 as *const libc::c_char, ); current_block = 17708497480799081542; } else { current_block = 7333393191927787629; } } else { current_block = 7333393191927787629; } if current_block != 17708497480799081542 { end_mark = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlTagToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh234 = addr_of_mut!((*token).data.tag.handle); *fresh234 = handle; let fresh235 = addr_of_mut!((*token).data.tag.suffix); *fresh235 = suffix; return OK; } } } yaml_free(handle as *mut libc::c_void); yaml_free(suffix as *mut libc::c_void); FAIL } unsafe fn yaml_parser_scan_tag_handle( parser: *mut YamlParserT, directive: bool, start_mark: YamlMarkT, handle: *mut *mut yaml_char_t, ) -> Success { let mut current_block: u64; let mut string = NULL_STRING; STRING_INIT!(string); if cache(parser, 1_u64).ok { if !CHECK!((*parser).buffer, b'!') { yaml_parser_set_scanner_error( parser, if directive { b"while scanning a tag directive\0" as *const u8 as *const libc::c_char } else { b"while scanning a tag\0" as *const u8 as *const libc::c_char }, start_mark, b"did not find expected '!'\0" as *const u8 as *const libc::c_char, ); } else { read!(parser, string); if cache(parser, 1_u64).ok { loop { if !IS_ALPHA!((*parser).buffer) { current_block = 7651349459974463963; break; } read!(parser, string); if cache(parser, 1_u64).fail { current_block = 1771849829115608806; break; } } if current_block != 1771849829115608806 { if CHECK!((*parser).buffer, b'!') { read!(parser, string); current_block = 5689001924483802034; } else if directive && !(*string.start == b'!' && *string.start.wrapping_offset(1_isize) == b'\0') { yaml_parser_set_scanner_error( parser, b"while parsing a tag directive\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected '!'\0" as *const u8 as *const libc::c_char, ); current_block = 1771849829115608806; } else { current_block = 5689001924483802034; } if current_block != 1771849829115608806 { *handle = string.start; return OK; } } } } } STRING_DEL!(string); FAIL } unsafe fn yaml_parser_scan_tag_uri( parser: *mut YamlParserT, uri_char: bool, directive: bool, head: *mut yaml_char_t, start_mark: YamlMarkT, uri: *mut *mut yaml_char_t, ) -> Success { let mut current_block: u64; let mut length: size_t = if !head.is_null() { strlen(head as *mut libc::c_char) } else { 0_u64 }; let mut string = NULL_STRING; STRING_INIT!(string); current_block = 14916268686031723178; 'c_21953: loop { match current_block { 15265153392498847348 => { STRING_DEL!(string); return FAIL; } _ => { if string.end.c_offset_from(string.start) as size_t <= length { yaml_string_extend( addr_of_mut!(string.start), addr_of_mut!(string.pointer), addr_of_mut!(string.end), ); current_block = 14916268686031723178; continue; } else { if length > 1_u64 { let _ = memcpy( string.start as *mut libc::c_void, head.wrapping_offset(1_isize) as *const libc::c_void, length.wrapping_sub(1_u64), ); string.pointer = string.pointer.wrapping_offset( length.wrapping_sub(1_u64) as isize, ); } if cache(parser, 1_u64).fail { current_block = 15265153392498847348; continue; } while !(*parser).buffer.is_empty() && (IS_ALPHA!((*parser).buffer) || CHECK!((*parser).buffer, b';') || CHECK!((*parser).buffer, b'/') || CHECK!((*parser).buffer, b'?') || CHECK!((*parser).buffer, b':') || CHECK!((*parser).buffer, b'@') || CHECK!((*parser).buffer, b'&') || CHECK!((*parser).buffer, b'=') || CHECK!((*parser).buffer, b'+') || CHECK!((*parser).buffer, b'$') || CHECK!((*parser).buffer, b'.') || CHECK!((*parser).buffer, b'%') || CHECK!((*parser).buffer, b'!') || CHECK!((*parser).buffer, b'~') || CHECK!((*parser).buffer, b'*') || CHECK!((*parser).buffer, b'\'') || CHECK!((*parser).buffer, b'(') || CHECK!((*parser).buffer, b')') || uri_char && (CHECK!((*parser).buffer, b',') || CHECK!((*parser).buffer, b'[') || CHECK!((*parser).buffer, b']'))) { if CHECK!((*parser).buffer, b'%') { STRING_EXTEND!(string); if yaml_parser_scan_uri_escapes( parser, directive, start_mark, addr_of_mut!(string), ) .fail { current_block = 15265153392498847348; continue 'c_21953; } } else { read!(parser, string); } length = length.force_add(1); if cache(parser, 1_u64).fail { current_block = 15265153392498847348; continue 'c_21953; } } if length == 0 { STRING_EXTEND!(string); yaml_parser_set_scanner_error( parser, if directive { b"while parsing a %TAG directive\0" as *const u8 as *const libc::c_char } else { b"while parsing a tag\0" as *const u8 as *const libc::c_char }, start_mark, b"did not find expected tag URI\0" as *const u8 as *const libc::c_char, ); current_block = 15265153392498847348; } else { *uri = string.start; return OK; } } } } } } unsafe fn yaml_parser_scan_uri_escapes( parser: *mut YamlParserT, directive: bool, start_mark: YamlMarkT, string: *mut YamlStringT, ) -> Success { let mut width: libc::c_int = 0; loop { if cache(parser, 3_u64).fail { return FAIL; } if !(CHECK!((*parser).buffer, b'%') && IS_HEX_AT!((*parser).buffer, 1) && IS_HEX_AT!((*parser).buffer, 2)) { yaml_parser_set_scanner_error( parser, if directive { b"while parsing a %TAG directive\0" as *const u8 as *const libc::c_char } else { b"while parsing a tag\0" as *const u8 as *const libc::c_char }, start_mark, b"did not find URI escaped octet\0" as *const u8 as *const libc::c_char, ); return FAIL; } let octet: libc::c_uchar = ((AS_HEX_AT!((*parser).buffer, 1) << 4) + AS_HEX_AT!((*parser).buffer, 2)) as libc::c_uchar; if width == 0 { width = if octet & 0x80 == 0 { 1 } else if octet & 0xE0 == 0xC0 { 2 } else if octet & 0xF0 == 0xE0 { 3 } else if octet & 0xF8 == 0xF0 { 4 } else { 0 }; if width == 0 { yaml_parser_set_scanner_error( parser, if directive { b"while parsing a %TAG directive\0" as *const u8 as *const libc::c_char } else { b"while parsing a tag\0" as *const u8 as *const libc::c_char }, start_mark, b"found an incorrect leading UTF-8 octet\0" as *const u8 as *const libc::c_char, ); return FAIL; } } else if octet & 0xC0 != 0x80 { yaml_parser_set_scanner_error( parser, if directive { b"while parsing a %TAG directive\0" as *const u8 as *const libc::c_char } else { b"while parsing a tag\0" as *const u8 as *const libc::c_char }, start_mark, b"found an incorrect trailing UTF-8 octet\0" as *const u8 as *const libc::c_char, ); return FAIL; } let fresh368 = addr_of_mut!((*string).pointer); let fresh369 = *fresh368; *fresh368 = (*fresh368).wrapping_offset(1); *fresh369 = octet; skip(parser); skip(parser); skip(parser); width -= 1; if width == 0 { break; } } OK } unsafe fn yaml_parser_scan_block_scalar( parser: *mut YamlParserT, token: *mut YamlTokenT, literal: bool, ) -> Success { let mut current_block: u64; let mut end_mark: YamlMarkT; let mut string = NULL_STRING; let mut leading_break = NULL_STRING; let mut trailing_breaks = NULL_STRING; let mut chomping: libc::c_int = 0; let mut increment: libc::c_int = 0; let mut indent: libc::c_int = 0; let mut leading_blank: libc::c_int = 0; let mut trailing_blank: libc::c_int; STRING_INIT!(string); STRING_INIT!(leading_break); STRING_INIT!(trailing_breaks); let start_mark: YamlMarkT = (*parser).mark; skip(parser); if cache(parser, 1_u64).ok { if CHECK!((*parser).buffer, b'+') || CHECK!((*parser).buffer, b'-') { chomping = if CHECK!((*parser).buffer, b'+') { 1 } else { -1 }; skip(parser); if cache(parser, 1_u64).fail { current_block = 14984465786483313892; } else if IS_DIGIT!((*parser).buffer) { if CHECK!((*parser).buffer, b'0') { yaml_parser_set_scanner_error( parser, b"while scanning a block scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found an indentation indicator equal to 0\0" as *const u8 as *const libc::c_char, ); current_block = 14984465786483313892; } else { increment = AS_DIGIT!((*parser).buffer); skip(parser); current_block = 11913429853522160501; } } else { current_block = 11913429853522160501; } } else if IS_DIGIT!((*parser).buffer) { if CHECK!((*parser).buffer, b'0') { yaml_parser_set_scanner_error( parser, b"while scanning a block scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found an indentation indicator equal to 0\0" as *const u8 as *const libc::c_char, ); current_block = 14984465786483313892; } else { increment = AS_DIGIT!((*parser).buffer); skip(parser); if cache(parser, 1_u64).fail { current_block = 14984465786483313892; } else { if CHECK!((*parser).buffer, b'+') || CHECK!((*parser).buffer, b'-') { chomping = if CHECK!((*parser).buffer, b'+') { 1 } else { -1 }; skip(parser); } current_block = 11913429853522160501; } } } else { current_block = 11913429853522160501; } if current_block != 14984465786483313892 && cache(parser, 1_u64).ok { loop { if !IS_BLANK!((*parser).buffer) { current_block = 4090602189656566074; break; } skip(parser); if cache(parser, 1_u64).fail { current_block = 14984465786483313892; break; } } if current_block != 14984465786483313892 { if CHECK!((*parser).buffer, b'#') { loop { if IS_BREAKZ!((*parser).buffer) { current_block = 12997042908615822766; break; } skip(parser); if cache(parser, 1_u64).fail { current_block = 14984465786483313892; break; } } } else { current_block = 12997042908615822766; } if current_block != 14984465786483313892 { if !IS_BREAKZ!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a block scalar\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected comment or line break\0" as *const u8 as *const libc::c_char, ); } else { if IS_BREAK!((*parser).buffer) { if cache(parser, 2_u64).fail { current_block = 14984465786483313892; } else { skip_line(parser); current_block = 13619784596304402172; } } else { current_block = 13619784596304402172; } if current_block != 14984465786483313892 { end_mark = (*parser).mark; if increment != 0 { indent = if (*parser).indent >= 0 { (*parser).indent + increment } else { increment }; } if yaml_parser_scan_block_scalar_breaks( parser, addr_of_mut!(indent), addr_of_mut!(trailing_breaks), start_mark, addr_of_mut!(end_mark), ) .ok && cache(parser, 1_u64).ok { 's_281: loop { if (*parser).mark.column as libc::c_int != indent || IS_Z!((*parser).buffer) { current_block = 5793491756164225964; break; } trailing_blank = IS_BLANK!((*parser).buffer) as libc::c_int; if !literal && *leading_break.start == b'\n' && leading_blank == 0 && trailing_blank == 0 { if *trailing_breaks.start == b'\0' { STRING_EXTEND!(string); let fresh418 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh418 = b' '; } CLEAR!(leading_break); } else { JOIN!(string, leading_break); CLEAR!(leading_break); } JOIN!(string, trailing_breaks); CLEAR!(trailing_breaks); leading_blank = IS_BLANK!((*parser).buffer) as libc::c_int; while !IS_BREAKZ!((*parser).buffer) { read!(parser, string); if cache(parser, 1_u64).fail { current_block = 14984465786483313892; break 's_281; } } if cache(parser, 2_u64).fail { current_block = 14984465786483313892; break; } read_line!(parser, leading_break); if yaml_parser_scan_block_scalar_breaks( parser, addr_of_mut!(indent), addr_of_mut!(trailing_breaks), start_mark, addr_of_mut!(end_mark), ) .fail { current_block = 14984465786483313892; break; } } if current_block != 14984465786483313892 { if chomping != -1 { JOIN!(string, leading_break); current_block = 17787701279558130514; } else { current_block = 17787701279558130514; } if current_block != 14984465786483313892 { if chomping == 1 { JOIN!( string, trailing_breaks ); } let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlScalarToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh479 = addr_of_mut!( (*token).data.scalar.value ); *fresh479 = string.start; (*token).data.scalar.length = string .pointer .c_offset_from( string.start, ) as size_t; (*token).data.scalar.style = if literal { YamlLiteralScalarStyle } else { YamlFoldedScalarStyle }; STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); return OK; } } } } } } } } } STRING_DEL!(string); STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); FAIL } unsafe fn yaml_parser_scan_block_scalar_breaks( parser: *mut YamlParserT, indent: *mut libc::c_int, breaks: *mut YamlStringT, start_mark: YamlMarkT, end_mark: *mut YamlMarkT, ) -> Success { let mut max_indent: libc::c_int = 0; *end_mark = (*parser).mark; loop { if cache(parser, 1_u64).fail { return FAIL; } while (*indent == 0 || ((*parser).mark.column as libc::c_int) < *indent) && IS_SPACE!((*parser).buffer) { skip(parser); if cache(parser, 1_u64).fail { return FAIL; } } if (*parser).mark.column as libc::c_int > max_indent { max_indent = (*parser).mark.column as libc::c_int; } if (*indent == 0 || ((*parser).mark.column as libc::c_int) < *indent) && IS_TAB!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a block scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found a tab character where an indentation space is expected\0" as *const u8 as *const libc::c_char, ); return FAIL; } if !IS_BREAK!((*parser).buffer) { break; } if cache(parser, 2_u64).fail { return FAIL; } read_line!(parser, *breaks); *end_mark = (*parser).mark; } if *indent == 0 { *indent = max_indent; if *indent < (*parser).indent + 1 { *indent = (*parser).indent + 1; } if *indent < 1 { *indent = 1; } } OK } unsafe fn yaml_parser_scan_flow_scalar( parser: *mut YamlParserT, token: *mut YamlTokenT, single: bool, ) -> Success { let current_block: u64; let end_mark: YamlMarkT; let mut string = NULL_STRING; let mut leading_break = NULL_STRING; let mut trailing_breaks = NULL_STRING; let mut whitespaces = NULL_STRING; let mut leading_blanks; STRING_INIT!(string); STRING_INIT!(leading_break); STRING_INIT!(trailing_breaks); STRING_INIT!(whitespaces); let start_mark: YamlMarkT = (*parser).mark; skip(parser); 's_58: loop { if cache(parser, 4_u64).fail { current_block = 8114179180390253173; break; } if (*parser).mark.column == 0_u64 && (CHECK_AT!((*parser).buffer, b'-', 0) && CHECK_AT!((*parser).buffer, b'-', 1) && CHECK_AT!((*parser).buffer, b'-', 2) || CHECK_AT!((*parser).buffer, b'.', 0) && CHECK_AT!((*parser).buffer, b'.', 1) && CHECK_AT!((*parser).buffer, b'.', 2)) && IS_BLANKZ_AT!((*parser).buffer, 3) { yaml_parser_set_scanner_error( parser, b"while scanning a quoted scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found unexpected document indicator\0" as *const u8 as *const libc::c_char, ); current_block = 8114179180390253173; break; } else if IS_Z!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a quoted scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found unexpected end of stream\0" as *const u8 as *const libc::c_char, ); current_block = 8114179180390253173; break; } else { if cache(parser, 2_u64).fail { current_block = 8114179180390253173; break; } leading_blanks = false; while !IS_BLANKZ!((*parser).buffer) { if single && CHECK_AT!((*parser).buffer, b'\'', 0) && CHECK_AT!((*parser).buffer, b'\'', 1) { STRING_EXTEND!(string); let fresh521 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh521 = b'\''; skip(parser); skip(parser); } else { if CHECK!( (*parser).buffer, if single { b'\'' } else { b'"' } ) { break; } if !single && CHECK!((*parser).buffer, b'\\') && IS_BREAK_AT!((*parser).buffer, 1) { if cache(parser, 3_u64).fail { current_block = 8114179180390253173; break 's_58; } skip(parser); skip_line(parser); leading_blanks = true; break; } else if !single && CHECK!((*parser).buffer, b'\\') { let mut code_length: size_t = 0_u64; STRING_EXTEND!(string); match *(*parser) .buffer .pointer .wrapping_offset(1_isize) { b'0' => { let fresh542 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh542 = b'\0'; } b'a' => { let fresh543 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh543 = b'\x07'; } b'b' => { let fresh544 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh544 = b'\x08'; } b't' | b'\t' => { let fresh545 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh545 = b'\t'; } b'n' => { let fresh546 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh546 = b'\n'; } b'v' => { let fresh547 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh547 = b'\x0B'; } b'f' => { let fresh548 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh548 = b'\x0C'; } b'r' => { let fresh549 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh549 = b'\r'; } b'e' => { let fresh550 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh550 = b'\x1B'; } b' ' => { let fresh551 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh551 = b' '; } b'"' => { let fresh552 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh552 = b'"'; } b'/' => { let fresh553 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh553 = b'/'; } b'\\' => { let fresh554 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh554 = b'\\'; } // NEL (#x85) b'N' => { let fresh555 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh555 = b'\xC2'; let fresh556 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh556 = b'\x85'; } // #xA0 b'_' => { let fresh557 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh557 = b'\xC2'; let fresh558 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh558 = b'\xA0'; } // LS (#x2028) b'L' => { let fresh559 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh559 = b'\xE2'; let fresh560 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh560 = b'\x80'; let fresh561 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh561 = b'\xA8'; } // PS (#x2029) b'P' => { let fresh562 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh562 = b'\xE2'; let fresh563 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh563 = b'\x80'; let fresh564 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh564 = b'\xA9'; } b'x' => { code_length = 2_u64; } b'u' => { code_length = 4_u64; } b'U' => { code_length = 8_u64; } _ => { yaml_parser_set_scanner_error( parser, b"while parsing a quoted scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found unknown escape character\0" as *const u8 as *const libc::c_char, ); current_block = 8114179180390253173; break 's_58; } } skip(parser); skip(parser); if code_length != 0 { let mut value: libc::c_uint = 0; let mut k: size_t; if cache(parser, code_length).fail { current_block = 8114179180390253173; break 's_58; } k = 0_u64; while k < code_length { if !IS_HEX_AT!( (*parser).buffer, k as isize ) { yaml_parser_set_scanner_error( parser, b"while parsing a quoted scalar\0" as *const u8 as *const libc::c_char, start_mark, b"did not find expected hexadecimal number\0" as *const u8 as *const libc::c_char, ); current_block = 8114179180390253173; break 's_58; } else { value = (value << 4).force_add( AS_HEX_AT!( (*parser).buffer, k as isize ) as libc::c_uint, ); k = k.force_add(1); } } if (0xD800..=0xDFFF).contains(&value) || value > 0x10FFFF { yaml_parser_set_scanner_error( parser, b"while parsing a quoted scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found invalid Unicode character escape code\0" as *const u8 as *const libc::c_char, ); current_block = 8114179180390253173; break 's_58; } else { if value <= 0x7F { let fresh573 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh573 = value as yaml_char_t; } else if value <= 0x7FF { let fresh574 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh574 = 0xC0_u32 .force_add(value >> 6) as yaml_char_t; let fresh575 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh575 = 0x80_u32 .force_add(value & 0x3F) as yaml_char_t; } else if value <= 0xFFFF { let fresh576 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh576 = 0xE0_u32 .force_add(value >> 12) as yaml_char_t; let fresh577 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh577 = 0x80_u32 .force_add(value >> 6 & 0x3F) as yaml_char_t; let fresh578 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh578 = 0x80_u32 .force_add(value & 0x3F) as yaml_char_t; } else { let fresh579 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh579 = 0xF0_u32 .force_add(value >> 18) as yaml_char_t; let fresh580 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh580 = 0x80_u32 .force_add(value >> 12 & 0x3F) as yaml_char_t; let fresh581 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh581 = 0x80_u32 .force_add(value >> 6 & 0x3F) as yaml_char_t; let fresh582 = string.pointer; string.pointer = string .pointer .wrapping_offset(1); *fresh582 = 0x80_u32 .force_add(value & 0x3F) as yaml_char_t; } k = 0_u64; while k < code_length { skip(parser); k = k.force_add(1); } } } } else { read!(parser, string); } } if cache(parser, 2_u64).fail { current_block = 8114179180390253173; break 's_58; } } if cache(parser, 1_u64).fail { current_block = 8114179180390253173; break; } if CHECK!( (*parser).buffer, if single { b'\'' } else { b'"' } ) { current_block = 7468767852762055642; break; } if cache(parser, 1_u64).fail { current_block = 8114179180390253173; break; } while IS_BLANK!((*parser).buffer) || IS_BREAK!((*parser).buffer) { if IS_BLANK!((*parser).buffer) { if !leading_blanks { read!(parser, whitespaces); } else { skip(parser); } } else { if cache(parser, 2_u64).fail { current_block = 8114179180390253173; break 's_58; } if !leading_blanks { CLEAR!(whitespaces); read_line!(parser, leading_break); leading_blanks = true; } else { read_line!(parser, trailing_breaks); } } if cache(parser, 1_u64).fail { current_block = 8114179180390253173; break 's_58; } } if leading_blanks { if *leading_break.start == b'\n' { if *trailing_breaks.start == b'\0' { STRING_EXTEND!(string); let fresh711 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh711 = b' '; } else { JOIN!(string, trailing_breaks); CLEAR!(trailing_breaks); } CLEAR!(leading_break); } else { JOIN!(string, leading_break); JOIN!(string, trailing_breaks); CLEAR!(leading_break); CLEAR!(trailing_breaks); } } else { JOIN!(string, whitespaces); CLEAR!(whitespaces); } } } if current_block != 8114179180390253173 { skip(parser); end_mark = (*parser).mark; let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlScalarToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh716 = addr_of_mut!((*token).data.scalar.value); *fresh716 = string.start; (*token).data.scalar.length = string.pointer.c_offset_from(string.start) as size_t; (*token).data.scalar.style = if single { YamlSingleQuotedScalarStyle } else { YamlDoubleQuotedScalarStyle }; STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); STRING_DEL!(whitespaces); return OK; } STRING_DEL!(string); STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); STRING_DEL!(whitespaces); FAIL } unsafe fn yaml_parser_scan_plain_scalar( parser: *mut YamlParserT, token: *mut YamlTokenT, ) -> Success { let current_block: u64; let mut end_mark: YamlMarkT; let mut string = NULL_STRING; let mut leading_break = NULL_STRING; let mut trailing_breaks = NULL_STRING; let mut whitespaces = NULL_STRING; let mut leading_blanks = false; let indent: libc::c_int = (*parser).indent + 1; STRING_INIT!(string); STRING_INIT!(leading_break); STRING_INIT!(trailing_breaks); STRING_INIT!(whitespaces); end_mark = (*parser).mark; let start_mark: YamlMarkT = end_mark; 's_57: loop { if cache(parser, 4_u64).fail { current_block = 16642808987012640029; break; } if (*parser).mark.column == 0_u64 && (CHECK_AT!((*parser).buffer, b'-', 0) && CHECK_AT!((*parser).buffer, b'-', 1) && CHECK_AT!((*parser).buffer, b'-', 2) || CHECK_AT!((*parser).buffer, b'.', 0) && CHECK_AT!((*parser).buffer, b'.', 1) && CHECK_AT!((*parser).buffer, b'.', 2)) && IS_BLANKZ_AT!((*parser).buffer, 3) { current_block = 6281126495347172768; break; } if CHECK!((*parser).buffer, b'#') { current_block = 6281126495347172768; break; } while !IS_BLANKZ!((*parser).buffer) { if (*parser).flow_level != 0 && CHECK!((*parser).buffer, b':') && (CHECK_AT!((*parser).buffer, b',', 1) || CHECK_AT!((*parser).buffer, b'?', 1) || CHECK_AT!((*parser).buffer, b'[', 1) || CHECK_AT!((*parser).buffer, b']', 1) || CHECK_AT!((*parser).buffer, b'{', 1) || CHECK_AT!((*parser).buffer, b'}', 1)) { yaml_parser_set_scanner_error( parser, b"while scanning a plain scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found unexpected ':'\0" as *const u8 as *const libc::c_char, ); current_block = 16642808987012640029; break 's_57; } else { if CHECK!((*parser).buffer, b':') && IS_BLANKZ_AT!((*parser).buffer, 1) || (*parser).flow_level != 0 && (CHECK!((*parser).buffer, b',') || CHECK!((*parser).buffer, b'[') || CHECK!((*parser).buffer, b']') || CHECK!((*parser).buffer, b'{') || CHECK!((*parser).buffer, b'}')) { break; } if leading_blanks || whitespaces.start != whitespaces.pointer { if leading_blanks { if *leading_break.start == b'\n' { if *trailing_breaks.start == b'\0' { STRING_EXTEND!(string); let fresh717 = string.pointer; string.pointer = string.pointer.wrapping_offset(1); *fresh717 = b' '; } else { JOIN!(string, trailing_breaks); CLEAR!(trailing_breaks); } CLEAR!(leading_break); } else { JOIN!(string, leading_break); JOIN!(string, trailing_breaks); CLEAR!(leading_break); CLEAR!(trailing_breaks); } leading_blanks = false; } else { JOIN!(string, whitespaces); CLEAR!(whitespaces); } } read!(parser, string); end_mark = (*parser).mark; if cache(parser, 2_u64).fail { current_block = 16642808987012640029; break 's_57; } } } if !(IS_BLANK!((*parser).buffer) || IS_BREAK!((*parser).buffer)) { current_block = 6281126495347172768; break; } if cache(parser, 1_u64).fail { current_block = 16642808987012640029; break; } while IS_BLANK!((*parser).buffer) || IS_BREAK!((*parser).buffer) { if IS_BLANK!((*parser).buffer) { if leading_blanks && ((*parser).mark.column as libc::c_int) < indent && IS_TAB!((*parser).buffer) { yaml_parser_set_scanner_error( parser, b"while scanning a plain scalar\0" as *const u8 as *const libc::c_char, start_mark, b"found a tab character that violates indentation\0" as *const u8 as *const libc::c_char, ); current_block = 16642808987012640029; break 's_57; } else if !leading_blanks { read!(parser, whitespaces); } else { skip(parser); } } else { if cache(parser, 2_u64).fail { current_block = 16642808987012640029; break 's_57; } if !leading_blanks { CLEAR!(whitespaces); read_line!(parser, leading_break); leading_blanks = true; } else { read_line!(parser, trailing_breaks); } } if cache(parser, 1_u64).fail { current_block = 16642808987012640029; break 's_57; } } if (*parser).flow_level == 0 && ((*parser).mark.column as libc::c_int) < indent { current_block = 6281126495347172768; break; } } if current_block != 16642808987012640029 { let _ = memset( token as *mut libc::c_void, 0, size_of::() as libc::c_ulong, ); (*token).type_ = YamlScalarToken; (*token).start_mark = start_mark; (*token).end_mark = end_mark; let fresh842 = addr_of_mut!((*token).data.scalar.value); *fresh842 = string.start; (*token).data.scalar.length = string.pointer.c_offset_from(string.start) as size_t; (*token).data.scalar.style = YamlPlainScalarStyle; if leading_blanks { (*parser).simple_key_allowed = true; } STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); STRING_DEL!(whitespaces); return OK; } STRING_DEL!(string); STRING_DEL!(leading_break); STRING_DEL!(trailing_breaks); STRING_DEL!(whitespaces); FAIL } libyml-0.0.5/src/string.rs000064400000000000000000000070371046102023000135700ustar 00000000000000use crate::{ externs::memset, libc, memory::{yaml_realloc, yaml_strdup}, yaml::{size_t, yaml_char_t}, }; /// Extend a string buffer by reallocating and copying the existing data. /// /// This function is used to grow a string buffer when more space is needed. /// /// # Safety /// /// - This function is unsafe because it directly calls the system's `realloc` and /// `memset` functions, which can lead to undefined behaviour if misused. /// - The caller must ensure that `start`, `pointer`, and `end` are valid pointers /// into the same allocated memory block. /// - The caller must ensure that the memory block being extended is large enough /// to accommodate the new size. /// - The caller is responsible for properly freeing the extended memory block using /// the corresponding `yaml_free` function when it is no longer needed. /// pub unsafe fn yaml_string_extend( start: *mut *mut yaml_char_t, pointer: *mut *mut yaml_char_t, end: *mut *mut yaml_char_t, ) { let current_size = (*end).offset_from(*start) as size_t; let new_size = current_size * 2; let new_start: *mut yaml_char_t = yaml_realloc(*start as *mut libc::c_void, new_size) as *mut yaml_char_t; let _ = memset( new_start.add(current_size.try_into().unwrap()) as *mut libc::c_void, 0, current_size, ); let offset = (*pointer).offset_from(*start); *pointer = new_start.add(offset.try_into().unwrap()); *end = new_start.add((new_size as isize).try_into().unwrap()); *start = new_start; } /// Duplicate a null-terminated string. /// # Safety /// - This function is unsafe because it involves memory allocation. pub unsafe fn yaml_string_duplicate( str: *const yaml_char_t, ) -> *mut yaml_char_t { yaml_strdup(str) } /// Join two string buffers by copying data from one to the other. /// /// This function is used to concatenate two string buffers. /// /// # Safety /// /// - This function is unsafe because it directly calls the system's `memcpy` function, /// which can lead to undefined behaviour if misused. /// - The caller must ensure that `a_start`, `a_pointer`, `a_end`, `b_start`, `b_pointer`, /// and `b_end` are valid pointers into their respective allocated memory blocks. /// - The caller must ensure that the memory blocks being joined are large enough to /// accommodate the combined data. /// - The caller is responsible for properly freeing the joined memory block using /// the corresponding `yaml_free` function when it is no longer needed. /// pub unsafe fn yaml_string_join( a_start: *mut *mut yaml_char_t, a_pointer: *mut *mut yaml_char_t, a_end: *mut *mut yaml_char_t, b_start: *mut *mut yaml_char_t, b_pointer: *mut *mut yaml_char_t, b_end: *mut *mut yaml_char_t, ) { // If b_start is equal to b_pointer, there's nothing to join if *b_start == *b_pointer { return; } // Calculate the length of the data in b let b_length = ((*b_pointer).offset_from(*b_start)) .min((*b_end).offset_from(*b_start)) as usize; // If the length of b is 0, there's nothing to copy if b_length == 0 { return; } // Ensure there's enough space in a to hold b's content while ((*a_end).offset_from(*a_pointer) as usize) < b_length { yaml_string_extend(a_start, a_pointer, a_end); } // Copy b's content to a core::ptr::copy_nonoverlapping(*b_start, *a_pointer, b_length); // Move a's pointer forward by the length of the copied data *a_pointer = (*a_pointer).add(b_length); } libyml-0.0.5/src/success.rs000064400000000000000000000037201046102023000137250ustar 00000000000000use core::ops::Deref; /// Constant representing a successful operation. pub const OK: Success = Success { ok: true }; /// Constant representing a failed operation. pub const FAIL: Success = Success { ok: false }; /// Structure representing the success state of an operation. #[must_use] #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Success { /// Boolean indicating whether the operation was successful. pub ok: bool, } /// Structure representing the failure state of an operation. #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Failure { /// Boolean indicating whether the operation failed. pub fail: bool, } impl Deref for Success { type Target = Failure; /// Returns a reference to the corresponding `Failure` instance based on the success state. fn deref(&self) -> &Self::Target { if self.ok { &Failure { fail: false } } else { &Failure { fail: true } } } } /// Checks if the given `Success` result indicates a successful operation. /// /// # Arguments /// /// * `result` - A `Success` struct representing the result of an operation. /// /// # Returns /// /// * `true` if the operation was successful. /// * `false` if the operation failed. pub fn is_success(result: Success) -> bool { result.ok } /// Checks if the given `Success` result indicates a failure operation. /// /// # Arguments /// /// * `result` - A `Success` struct representing the result of an operation. /// /// # Returns /// /// * `true` if the operation failed. /// * `false` if the operation was successful. pub fn is_failure(result: Success) -> bool { !result.ok } #[cfg(test)] mod tests { use super::*; #[test] fn test_is_success() { assert!(is_success(OK)); assert!(!is_success(FAIL)); } #[test] fn test_deref() { let success = OK; let failure = FAIL; assert!(!success.deref().fail); assert!(failure.deref().fail); } } libyml-0.0.5/src/utils/memory_macros.rs000064400000000000000000000127041046102023000162730ustar 00000000000000//! Macros for memory management operations. //! //! This module provides a set of macros that wrap the unsafe memory management //! functions, providing a slightly safer interface while still allowing //! for low-level memory operations in a no_std environment. /// Allocates memory using the system's `malloc` function. /// /// This macro wraps the `yaml_malloc` function, providing a more Rust-like interface. /// /// # Arguments /// /// * `size` - The number of bytes to allocate. /// /// # Returns /// /// Returns a `*mut T` pointer to the allocated memory, or `None` if the allocation failed. /// /// # Safety /// /// While this macro provides a safer interface than direct use of `yaml_malloc`, /// it is still unsafe because: /// - It allocates uninitialized memory. /// - The caller is responsible for properly freeing the allocated memory using `yaml_free!`. /// - The caller must ensure the allocated memory is properly initialized before use. /// /// # Examples /// /// ``` /// use libyml::{yaml_malloc,yaml_free}; /// /// let size = 1024; /// unsafe { /// if let Some(ptr) = yaml_malloc!(u8, size) { /// // Use the allocated memory /// // ... /// yaml_free!(ptr); /// } /// } /// ``` #[macro_export] macro_rules! yaml_malloc { ($t:ty, $size:expr) => {{ let ptr = unsafe { $crate::memory::yaml_malloc($size) }; if ptr.is_null() { None } else { Some(ptr as *mut $t) } }}; } /// Reallocates memory using the system's `realloc` function. /// /// This macro wraps the `yaml_realloc` function, providing a more Rust-like interface. /// /// # Arguments /// /// * `ptr` - A pointer to the memory block to reallocate. /// * `size` - The new size of the memory block in bytes. /// /// # Returns /// /// Returns a `*mut T` pointer to the reallocated memory, or `None` if the reallocation failed. /// /// # Safety /// /// While this macro provides a safer interface than direct use of `yaml_realloc`, /// it is still unsafe because: /// - It may move the memory to a new location. /// - The caller must ensure that `ptr` was previously allocated by `yaml_malloc!` or `yaml_realloc!`. /// - The caller is responsible for properly freeing the reallocated memory using `yaml_free!`. /// - The contents of the reallocated memory beyond the original size are undefined. /// /// # Examples /// /// ``` /// use libyml::{yaml_malloc, yaml_realloc, yaml_free}; /// /// unsafe { /// let mut size = 1024; /// if let Some(mut ptr) = yaml_malloc!(u8, size) { /// // Use the allocated memory /// // ... /// size = 2048; /// if let Some(new_ptr) = yaml_realloc!(ptr, u8, size) { /// ptr = new_ptr; /// // Use the reallocated memory /// // ... /// yaml_free!(ptr); /// } /// } /// } /// ``` #[macro_export] macro_rules! yaml_realloc { ($ptr:expr, $t:ty, $size:expr) => {{ let new_ptr = unsafe { $crate::memory::yaml_realloc($ptr as *mut _, $size) }; if new_ptr.is_null() { None } else { Some(new_ptr as *mut $t) } }}; } /// Frees memory allocated by `yaml_malloc!` or `yaml_realloc!`. /// /// This macro wraps the `yaml_free` function, providing a more Rust-like interface. /// /// # Arguments /// /// * `ptr` - A pointer to the memory block to free. /// /// # Safety /// /// While this macro provides a safer interface than direct use of `yaml_free`, /// it is still unsafe because: /// - The caller must ensure that `ptr` was allocated by `yaml_malloc!` or `yaml_realloc!`. /// - After calling this macro, `ptr` becomes invalid and must not be used. /// /// # Examples /// /// ``` /// use libyml::{yaml_malloc, yaml_free}; /// /// unsafe { /// let size = 1024; /// if let Some(ptr) = yaml_malloc!(u8, size) { /// // Use the allocated memory /// // ... /// yaml_free!(ptr); /// // ptr is now invalid and must not be used /// } /// } /// ``` #[macro_export] macro_rules! yaml_free { ($ptr:expr) => { unsafe { $crate::memory::yaml_free($ptr as *mut _) } }; } /// Duplicates a string using the system's `malloc` function and manual copy. /// /// This macro wraps the `yaml_strdup` function, providing a more Rust-like interface. /// /// # Arguments /// /// * `str` - A pointer to the null-terminated string to duplicate. /// /// # Returns /// /// Returns a `*mut yaml_char_t` pointer to the newly allocated string, or `None` if the allocation failed or the input was null. /// /// # Safety /// /// While this macro provides a safer interface than direct use of `yaml_strdup`, /// it is still unsafe because: /// - It involves memory allocation and raw pointer manipulation. /// - The caller must ensure that `str` is a valid, null-terminated string. /// - The caller is responsible for freeing the returned pointer using `yaml_free!`. /// /// # Examples /// /// ``` /// use libyml::yaml::yaml_char_t; /// use libyml::{yaml_strdup, yaml_free}; /// /// unsafe { /// let original = b"Hello, world!\0".as_ptr() as *const yaml_char_t; /// if let Some(copy) = yaml_strdup!(original) { /// // Use the duplicated string /// // ... /// yaml_free!(copy); /// } /// } /// ``` #[macro_export] macro_rules! yaml_strdup { ($str:expr) => {{ let new_str = unsafe { $crate::memory::yaml_strdup($str) }; if new_str.is_null() { None } else { Some(new_str) } }}; } libyml-0.0.5/src/utils/mod.rs000064400000000000000000000000771046102023000141760ustar 00000000000000/// A macro for `memory_macros` module. pub mod memory_macros; libyml-0.0.5/src/writer.rs000064400000000000000000000172131046102023000135730ustar 00000000000000use crate::{ libc, ops::ForceAdd as _, success::{Success, FAIL, OK}, yaml::size_t, PointerExt, YamlAnyEncoding, YamlEmitterT, YamlUtf16leEncoding, YamlUtf8Encoding, YamlWriterError, }; use core::ptr::addr_of_mut; /// Sets the writer error for the emitter. /// /// This function sets the error of the emitter and updates the problem string. /// /// # Arguments /// /// * `emitter` - A pointer to the YamlEmitterT struct. /// * `problem` - A pointer to the string that describes the error. /// /// # Returns /// /// * `Success::FAIL` - The function sets the error of the emitter and returns FAIL. /// /// # Safety /// /// This function is marked unsafe as it dereferences the pointer passed to it. /// The caller must ensure that the pointer is valid and points to a valid memory location. /// The caller must also ensure that the pointer is not null. /// pub(crate) unsafe fn yaml_emitter_set_writer_error( emitter: *mut YamlEmitterT, problem: *const libc::c_char, ) -> Success { (*emitter).error = YamlWriterError; let fresh0 = addr_of_mut!((*emitter).problem); *fresh0 = problem; FAIL } /// Flushes the buffer of the emitter and writes the content to the output stream. /// /// This function is called when the emitter needs to flush its buffer to the output stream. /// It first checks if the emitter is not null and if the write handler is not null. /// It also checks if the encoding of the emitter is not YamlAnyEncoding. /// /// If the conditions are met, it updates the last and pointer of the buffer. /// If the encoding is YamlUtf8Encoding, it writes the content of the buffer to the output stream. /// If an error occurs during the write operation, it sets the error of the emitter and returns FAIL. /// /// If the encoding is not YamlUtf8Encoding, it writes the content of the buffer to the raw buffer. /// It then writes the raw buffer to the output stream. /// If an error occurs during the write operation, it sets the error of the emitter and returns FAIL. /// If the write operation is successful, it returns OK. /// /// # Arguments /// /// * `emitter` - A pointer to the YamlEmitterT struct. /// /// # Returns /// /// * `Success` - An enum representing the success or failure of the operation. /// /// # Safety /// /// * The function is marked unsafe as it dereferences the pointer passed to it. /// * The caller must ensure that the pointer is valid and points to a valid memory location. /// * The caller must also ensure that the pointer is not null. /// * The caller must ensure that the write handler is not null. /// * The caller must ensure that the encoding is not YamlAnyEncoding. /// * The caller must ensure that the write handler is a valid function pointer. /// pub unsafe fn yaml_emitter_flush( emitter: *mut YamlEmitterT, ) -> Success { __assert!(!emitter.is_null()); __assert!(((*emitter).write_handler).is_some()); __assert!((*emitter).encoding != YamlAnyEncoding); let fresh1 = addr_of_mut!((*emitter).buffer.last); *fresh1 = (*emitter).buffer.pointer; let fresh2 = addr_of_mut!((*emitter).buffer.pointer); *fresh2 = (*emitter).buffer.start; if (*emitter).buffer.start == (*emitter).buffer.last { return OK; } if (*emitter).encoding == YamlUtf8Encoding { if (*emitter).write_handler.expect("non-null function pointer")( (*emitter).write_handler_data, (*emitter).buffer.start, (*emitter) .buffer .last .c_offset_from((*emitter).buffer.start) as size_t, ) != 0 { let fresh3 = addr_of_mut!((*emitter).buffer.last); *fresh3 = (*emitter).buffer.start; let fresh4 = addr_of_mut!((*emitter).buffer.pointer); *fresh4 = (*emitter).buffer.start; return OK; } else { return yaml_emitter_set_writer_error( emitter, b"write error\0" as *const u8 as *const libc::c_char, ); } } let low: libc::c_int = if (*emitter).encoding == YamlUtf16leEncoding { 0 } else { 1 }; let high: libc::c_int = if (*emitter).encoding == YamlUtf16leEncoding { 1 } else { 0 }; while (*emitter).buffer.pointer != (*emitter).buffer.last { let mut octet: libc::c_uchar; let mut value: libc::c_uint; let mut k: size_t; octet = *(*emitter).buffer.pointer; let width: libc::c_uint = if octet & 0x80 == 0 { 1 } else if octet & 0xE0 == 0xC0 { 2 } else if octet & 0xF0 == 0xE0 { 3 } else if octet & 0xF8 == 0xF0 { 4 } else { 0 } as libc::c_uint; value = if octet & 0x80 == 0 { octet & 0x7F } else if octet & 0xE0 == 0xC0 { octet & 0x1F } else if octet & 0xF0 == 0xE0 { octet & 0xF } else if octet & 0xF8 == 0xF0 { octet & 0x7 } else { 0 } as libc::c_uint; k = 1_u64; while k < width as libc::c_ulong { octet = *(*emitter).buffer.pointer.wrapping_offset(k as isize); value = (value << 6).force_add((octet & 0x3F) as libc::c_uint); k = k.force_add(1); } let fresh5 = addr_of_mut!((*emitter).buffer.pointer); *fresh5 = (*fresh5).wrapping_offset(width as isize); if value < 0x10000 { *(*emitter) .raw_buffer .last .wrapping_offset(high as isize) = (value >> 8) as libc::c_uchar; *(*emitter).raw_buffer.last.wrapping_offset(low as isize) = (value & 0xFF) as libc::c_uchar; let fresh6 = addr_of_mut!((*emitter).raw_buffer.last); *fresh6 = (*fresh6).wrapping_offset(2_isize); } else { value = value.wrapping_sub(0x10000); *(*emitter) .raw_buffer .last .wrapping_offset(high as isize) = 0xD8_u32.force_add(value >> 18) as libc::c_uchar; *(*emitter).raw_buffer.last.wrapping_offset(low as isize) = (value >> 10 & 0xFF) as libc::c_uchar; *(*emitter) .raw_buffer .last .wrapping_offset((high + 2) as isize) = 0xDC_u32.force_add(value >> 8 & 0xFF) as libc::c_uchar; *(*emitter) .raw_buffer .last .wrapping_offset((low + 2) as isize) = (value & 0xFF) as libc::c_uchar; let fresh7 = addr_of_mut!((*emitter).raw_buffer.last); *fresh7 = (*fresh7).wrapping_offset(4_isize); } } if (*emitter).write_handler.expect("non-null function pointer")( (*emitter).write_handler_data, (*emitter).raw_buffer.start, (*emitter) .raw_buffer .last .c_offset_from((*emitter).raw_buffer.start) as size_t, ) != 0 { let fresh8 = addr_of_mut!((*emitter).buffer.last); *fresh8 = (*emitter).buffer.start; let fresh9 = addr_of_mut!((*emitter).buffer.pointer); *fresh9 = (*emitter).buffer.start; let fresh10 = addr_of_mut!((*emitter).raw_buffer.last); *fresh10 = (*emitter).raw_buffer.start; let fresh11 = addr_of_mut!((*emitter).raw_buffer.pointer); *fresh11 = (*emitter).raw_buffer.start; OK } else { yaml_emitter_set_writer_error( emitter, b"write error\0" as *const u8 as *const libc::c_char, ) } } libyml-0.0.5/src/yaml.rs000064400000000000000000001263701046102023000132260ustar 00000000000000use crate::libc; use core::ops::Deref; use core::ptr::{self, addr_of}; pub(crate) use self::{ YamlEncodingT::*, YamlEventTypeT::*, YamlNodeTypeT::*, }; pub use core::primitive::{ i64 as ptrdiff_t, u64 as size_t, u8 as yaml_char_t, }; /// The version directive data. #[derive(Copy, Clone, Debug, Default)] #[repr(C)] #[non_exhaustive] pub struct YamlVersionDirectiveT { /// The major version number. pub major: libc::c_int, /// The minor version number. pub minor: libc::c_int, } impl YamlVersionDirectiveT { /// Constructor for `YamlVersionDirectiveT`. pub fn new(major: libc::c_int, minor: libc::c_int) -> Self { YamlVersionDirectiveT { major, minor, // Initialize any future fields with their default values } } } /// The tag directive data. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlTagDirectiveT { /// The tag handle. pub handle: *mut yaml_char_t, /// The tag prefix. pub prefix: *mut yaml_char_t, } /// The stream encoding. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlEncodingT { /// Let the parser choose the encoding. YamlAnyEncoding = 0, /// The default UTF-8 encoding. YamlUtf8Encoding = 1, /// The UTF-16-LE encoding with BOM. YamlUtf16leEncoding = 2, /// The UTF-16-BE encoding with BOM. YamlUtf16beEncoding = 3, } /// Line break type. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlBreakT { /// Let the parser choose the break type. YamlAnyBreak = 0, /// Use CR for line breaks (Mac style). YamlCrBreak = 1, /// Use LN for line breaks (Unix style). YamlLnBreak = 2, /// Use CR LN for line breaks (DOS style). YamlCrlnBreak = 3, } /// Many bad things could happen with the parser and emitter. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlErrorTypeT { /// No error. YamlNoError = 0, /// Cannot allocate or reallocate a block of memory. YamlMemoryError = 1, /// Cannot read or decode the input stream. YamlReaderError = 2, /// Cannot scan the input stream. YamlScannerError = 3, /// Cannot parse the input stream. YamlParserError = 4, /// Cannot compose a YAML document. YamlComposerError = 5, /// Cannot write to the output stream. YamlWriterError = 6, /// Cannot emit a YAML stream. YamlEmitterError = 7, } impl Default for YamlErrorTypeT { fn default() -> Self { YamlErrorTypeT::YamlNoError } } /// The pointer position. #[derive(Copy, Clone, Debug, Default)] #[repr(C)] #[non_exhaustive] pub struct YamlMarkT { /// The position index. pub index: size_t, /// The position line. pub line: size_t, /// The position column. pub column: size_t, } /// Scalar styles. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlScalarStyleT { /// Let the emitter choose the style. YamlAnyScalarStyle = 0, /// The plain scalar style. YamlPlainScalarStyle = 1, /// The single-quoted scalar style. YamlSingleQuotedScalarStyle = 2, /// The double-quoted scalar style. YamlDoubleQuotedScalarStyle = 3, /// The literal scalar style. YamlLiteralScalarStyle = 4, /// The folded scalar style. YamlFoldedScalarStyle = 5, } /// Sequence styles. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlSequenceStyleT { /// Let the emitter choose the style. YamlAnySequenceStyle = 0, /// The block sequence style. YamlBlockSequenceStyle = 1, /// The flow sequence style. YamlFlowSequenceStyle = 2, } /// Mapping styles. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlMappingStyleT { /// Let the emitter choose the style. YamlAnyMappingStyle = 0, /// The block mapping style. YamlBlockMappingStyle = 1, /// The flow mapping style. YamlFlowMappingStyle = 2, } /// The token types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlTokenTypeT { /// An empty token. YamlNoToken = 0, /// A stream-start token. YamlStreamStartToken = 1, /// A stream-end token. YamlStreamEndToken = 2, /// A version-directive token. YamlVersionDirectiveToken = 3, /// A tag-directive token. YamlTagDirectiveToken = 4, /// A document-start token. YamlDocumentStartToken = 5, /// A document-end token. YamlDocumentEndToken = 6, /// A block-sequence-start token. YamlBlockSequenceStartToken = 7, /// A block-mapping-start token. YamlBlockMappingStartToken = 8, /// A block-end token. YamlBlockEndToken = 9, /// A flow-sequence-start token. YamlFlowSequenceStartToken = 10, /// A flow-sequence-end token. YamlFlowSequenceEndToken = 11, /// A flow-mapping-start token. YamlFlowMappingStartToken = 12, /// A flow-mapping-end token. YamlFlowMappingEndToken = 13, /// A block-entry token. YamlBlockEntryToken = 14, /// A flow-entry token. YamlFlowEntryToken = 15, /// A key token. YamlKeyToken = 16, /// A value token. YamlValueToken = 17, /// An alias token. YamlAliasToken = 18, /// An anchor token. YamlAnchorToken = 19, /// A tag token. YamlTagToken = 20, /// A scalar token. YamlScalarToken = 21, } /// The token structure. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlTokenT { /// The token type. pub type_: YamlTokenTypeT, /// The token data. pub data: UnnamedYamlTokenTData, /// The beginning of the token. pub start_mark: YamlMarkT, /// The end of the token. pub end_mark: YamlMarkT, } #[derive(Copy, Clone, Debug, Default)] #[repr(C)] /// The data structure for YAML tokens. pub struct UnnamedYamlTokenTData { /// The stream start (for YamlStreamStartToken). pub stream_start: UnnamedYamlTokenTdataStreamStart, /// The alias (for YamlAliasToken). pub alias: UnnamedYamlTokenTdataAlias, /// The anchor (for YamlAnchorToken). pub anchor: UnnamedYamlTokenTdataAnchor, /// The tag (for YamlTagToken). pub tag: UnnamedYamlTokenTdataTag, /// The scalar value (for YamlScalarToken). pub scalar: UnnamedYamlTokenTdataScalar, /// The version directive (for YamlVersionDirectiveToken). pub version_directive: UnnamedYamlTokenTdataVersionDirective, /// The tag directive (for YamlTagDirectiveToken). pub tag_directive: UnnamedYamlTokenTdataTagDirective, } /// Represents the start of a YAML data stream. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataStreamStart { /// The stream encoding. pub encoding: YamlEncodingT, } /// Represents an alias in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataAlias { /// The alias value. pub value: *mut yaml_char_t, } /// Represents an anchor in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataAnchor { /// The anchor value. pub value: *mut yaml_char_t, } /// Represents a tag in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataTag { /// The tag handle. pub handle: *mut yaml_char_t, /// The tag suffix. pub suffix: *mut yaml_char_t, } /// Represents a scalar value in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataScalar { /// The scalar value. pub value: *mut yaml_char_t, /// The length of the scalar value. pub length: size_t, /// The scalar style. pub style: YamlScalarStyleT, } /// Represents the version directive in a YAML document. #[derive(Copy, Clone, Debug, Default)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataVersionDirective { /// The major version number. pub major: libc::c_int, /// The minor version number. pub minor: libc::c_int, } /// Represents the tag directive in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlTokenTdataTagDirective { /// The tag handle. pub handle: *mut yaml_char_t, /// The tag prefix. pub prefix: *mut yaml_char_t, } /// Event types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlEventTypeT { /// An empty event. YamlNoEvent = 0, /// A stream-start event. YamlStreamStartEvent = 1, /// A stream-end event. YamlStreamEndEvent = 2, /// A document-start event. YamlDocumentStartEvent = 3, /// A document-end event. YamlDocumentEndEvent = 4, /// An alias event. YamlAliasEvent = 5, /// A scalar event. YamlScalarEvent = 6, /// A sequence-start event. YamlSequenceStartEvent = 7, /// A sequence-end event. YamlSequenceEndEvent = 8, /// A mapping-start event. YamlMappingStartEvent = 9, /// A mapping-end event. YamlMappingEndEvent = 10, } /// The event structure. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlEventT { /// The event type. pub type_: YamlEventTypeT, /// The event data. pub data: UnnamedYamlEventTData, /// The beginning of the event. pub start_mark: YamlMarkT, /// The end of the event. pub end_mark: YamlMarkT, } /// Represents the data associated with a YAML event. #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct UnnamedYamlEventTData { /// The stream parameters (for YamlStreamStartEvent). pub stream_start: UnnamedYamlEventTdataStreamStart, /// The document parameters (for YamlDocumentStartEvent). pub document_start: UnnamedYamlEventTdataDocumentStart, /// The document end parameters (for YamlDocumentEndEvent). pub document_end: UnnamedYamlEventTdataDocumentEnd, /// The alias parameters (for YamlAliasEvent). pub alias: UnnamedYamlEventTdataAlias, /// The scalar parameters (for YamlScalarEvent). pub scalar: UnnamedYamlEventTdataScalar, /// The sequence parameters (for YamlSequenceStartEvent). pub sequence_start: UnnamedYamlEventTdataSequenceStart, /// The mapping parameters (for YamlMappingStartEvent). pub mapping_start: UnnamedYamlEventTdataMappingStart, } /// Represents the data associated with the start of a YAML stream. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataStreamStart { /// The document encoding. pub encoding: YamlEncodingT, } /// Represents the data associated with the start of a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataDocumentStart { /// The version directive. pub version_directive: *mut YamlVersionDirectiveT, /// The list of tag directives. pub tag_directives: UnnamedYamlEventTdataDocumentStartTagDirectives, /// Is the document indicator implicit? pub implicit: bool, } /// Represents the list of tag directives at the start of a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataDocumentStartTagDirectives { /// The beginning of the tag directives list. pub start: *mut YamlTagDirectiveT, /// The end of the tag directives list. pub end: *mut YamlTagDirectiveT, } /// Represents the data associated with the end of a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataDocumentEnd { /// Is the document end indicator implicit? pub implicit: bool, } /// Represents the data associated with a YAML alias event. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataAlias { /// The anchor. pub anchor: *mut yaml_char_t, } /// Represents the data associated with a YAML scalar event. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataScalar { /// The anchor. pub anchor: *mut yaml_char_t, /// The tag. pub tag: *mut yaml_char_t, /// The scalar value. pub value: *mut yaml_char_t, /// The length of the scalar value. pub length: size_t, /// Is the tag optional for the plain style? pub plain_implicit: bool, /// Is the tag optional for any non-plain style? pub quoted_implicit: bool, /// The scalar style. pub style: YamlScalarStyleT, } /// Represents the data associated with the start of a YAML sequence. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataSequenceStart { /// The anchor. pub anchor: *mut yaml_char_t, /// The tag. pub tag: *mut yaml_char_t, /// Is the tag optional? pub implicit: bool, /// The sequence style. pub style: YamlSequenceStyleT, } /// Represents the data associated with the start of a YAML mapping. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlEventTdataMappingStart { /// The anchor. pub anchor: *mut yaml_char_t, /// The tag. pub tag: *mut yaml_char_t, /// Is the tag optional? pub implicit: bool, /// The mapping style. pub style: YamlMappingStyleT, } /// Node types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlNodeTypeT { /// An empty node. YamlNoNode = 0, /// A scalar node. YamlScalarNode = 1, /// A sequence node. YamlSequenceNode = 2, /// A mapping node. YamlMappingNode = 3, } /// The node structure. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlNodeT { /// The node type. pub type_: YamlNodeTypeT, /// The node tag. pub tag: *mut yaml_char_t, /// The node data. pub data: UnnamedYamlNodeTData, /// The beginning of the node. pub start_mark: YamlMarkT, /// The end of the node. pub end_mark: YamlMarkT, } /// Represents the data associated with a YAML node. #[derive(Copy, Clone, Debug)] #[repr(C)] pub struct UnnamedYamlNodeTData { /// The scalar parameters (for YamlScalarNode). pub scalar: UnnamedYamlNodeTDataScalar, /// The sequence parameters (for YamlSequenceNode). pub sequence: UnnamedYamlNodeTDataSequence, /// The mapping parameters (for YamlMappingNode). pub mapping: UnnamedYamlNodeTDataMapping, } /// Represents the data associated with a YAML scalar node. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlNodeTDataScalar { /// The scalar value. pub value: *mut yaml_char_t, /// The length of the scalar value. pub length: size_t, /// The scalar style. pub style: YamlScalarStyleT, } /// Represents an element of a YAML sequence node. pub type YamlNodeItemT = libc::c_int; /// Represents the data associated with a YAML sequence node. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlNodeTDataSequence { /// The stack of sequence items. pub items: YamlStackT, /// The sequence style. pub style: YamlSequenceStyleT, } /// Represents the data associated with a YAML mapping node. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlNodeTDataMapping { /// The stack of mapping pairs (key, value). pub pairs: YamlStackT, /// The mapping style. pub style: YamlMappingStyleT, } /// An element of a mapping node. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlNodePairT { /// The key of the element. pub key: libc::c_int, /// The value of the element. pub value: libc::c_int, } /// The document structure. #[derive(Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlDocumentT { /// The document nodes. pub nodes: YamlStackT, /// The version directive. pub version_directive: *mut YamlVersionDirectiveT, /// The list of tag directives. pub tag_directives: UnnamedYamlDocumentTTagDirectives, /// Is the document start indicator implicit? pub start_implicit: bool, /// Is the document end indicator implicit? pub end_implicit: bool, /// The beginning of the document. pub start_mark: YamlMarkT, /// The end of the document. pub end_mark: YamlMarkT, } /// Represents the list of tag directives in a YAML document. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct UnnamedYamlDocumentTTagDirectives { /// The beginning of the tag directives list. pub start: *mut YamlTagDirectiveT, /// The end of the tag directives list. pub end: *mut YamlTagDirectiveT, } /// The prototype of a read handler. /// /// The read handler is called when the parser needs to read more bytes from the /// source. The handler should write not more than `size` bytes to the `buffer`. /// The number of written bytes should be set to the `length` variable. /// /// On success, the handler should return 1. If the handler failed, the returned /// value should be 0. On EOF, the handler should set the `size_read` to 0 and /// return 1. pub type YamlReadHandlerT = unsafe fn( data: *mut libc::c_void, buffer: *mut libc::c_uchar, size: size_t, size_read: *mut size_t, ) -> libc::c_int; /// This structure holds information about a potential simple key. #[derive(Copy, Clone, Debug, Default)] #[repr(C)] #[non_exhaustive] pub struct YamlSimpleKeyT { /// Is a simple key possible? pub possible: bool, /// Is a simple key required? pub required: bool, /// The number of the token. pub token_number: size_t, /// The position mark. pub mark: YamlMarkT, } /// The states of the parser. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlParserStateT { /// Expect stream-start. YamlParseStreamStartState = 0, /// Expect the beginning of an implicit document. YamlParseImplicitDocumentStartState = 1, /// Expect document-start. YamlParseDocumentStartState = 2, /// Expect the content of a document. YamlParseDocumentContentState = 3, /// Expect document-end. YamlParseDocumentEndState = 4, /// Expect a block node. YamlParseBlockNodeState = 5, /// Expect a block node or indentless sequence. YamlParseBlockNodeOrIndentlessSequenceState = 6, /// Expect a flow node. YamlParseFlowNodeState = 7, /// Expect the first entry of a block sequence. YamlParseBlockSequenceFirstEntryState = 8, /// Expect an entry of a block sequence. YamlParseBlockSequenceEntryState = 9, /// Expect an entry of an indentless sequence. YamlParseIndentlessSequenceEntryState = 10, /// Expect the first key of a block mapping. YamlParseBlockMappingFirstKeyState = 11, /// Expect a block mapping key. YamlParseBlockMappingKeyState = 12, /// Expect a block mapping value. YamlParseBlockMappingValueState = 13, /// Expect the first entry of a flow sequence. YamlParseFlowSequenceFirstEntryState = 14, /// Expect an entry of a flow sequence. YamlParseFlowSequenceEntryState = 15, /// Expect a key of an ordered mapping. YamlParseFlowSequenceEntryMappingKeyState = 16, /// Expect a value of an ordered mapping. YamlParseFlowSequenceEntryMappingValueState = 17, /// Expect the and of an ordered mapping entry. YamlParseFlowSequenceEntryMappingEndState = 18, /// Expect the first key of a flow mapping. YamlParseFlowMappingFirstKeyState = 19, /// Expect a key of a flow mapping. YamlParseFlowMappingKeyState = 20, /// Expect a value of a flow mapping. YamlParseFlowMappingValueState = 21, /// Expect an empty value of a flow mapping. YamlParseFlowMappingEmptyValueState = 22, /// Expect nothing. YamlParseEndState = 23, } /// This structure holds aliases data. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlAliasDataT { /// The anchor. pub anchor: *mut yaml_char_t, /// The node id. pub index: libc::c_int, /// The anchor mark. pub mark: YamlMarkT, } /// The parser structure. /// /// All members are internal. Manage the structure using the `yaml_parser_` /// family of functions. #[derive(Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlParserT { /// Error type. #[cfg(doc)] pub error: YamlErrorTypeT, #[cfg(not(doc))] pub(crate) error: YamlErrorTypeT, /// Error description. #[cfg(doc)] pub problem: *const libc::c_char, #[cfg(not(doc))] pub(crate) problem: *const libc::c_char, /// The byte about which the problem occurred. #[cfg(doc)] pub problem_offset: size_t, #[cfg(not(doc))] pub(crate) problem_offset: size_t, /// The problematic value (-1 is none). #[cfg(doc)] pub problem_value: libc::c_int, #[cfg(not(doc))] pub(crate) problem_value: libc::c_int, /// The problem position. #[cfg(doc)] pub problem_mark: YamlMarkT, #[cfg(not(doc))] pub(crate) problem_mark: YamlMarkT, /// The error context. #[cfg(doc)] pub context: *const libc::c_char, #[cfg(not(doc))] pub(crate) context: *const libc::c_char, /// The context position. #[cfg(doc)] pub context_mark: YamlMarkT, #[cfg(not(doc))] pub(crate) context_mark: YamlMarkT, /// Read handler. pub(crate) read_handler: Option, /// A pointer for passing to the read handler. pub(crate) read_handler_data: *mut libc::c_void, /// Standard (string or file) input data. pub(crate) input: UnnamedYamlParserTInput, /// EOF flag pub(crate) eof: bool, /// The working buffer. pub(crate) buffer: YamlBufferT, /// The number of unread characters in the buffer. pub(crate) unread: size_t, /// The raw buffer. pub(crate) raw_buffer: YamlBufferT, /// The input encoding. pub(crate) encoding: YamlEncodingT, /// The offset of the current position (in bytes). pub(crate) offset: size_t, /// The mark of the current position. pub(crate) mark: YamlMarkT, /// Have we started to scan the input stream? pub(crate) stream_start_produced: bool, /// Have we reached the end of the input stream? pub(crate) stream_end_produced: bool, /// The number of unclosed '[' and '{' indicators. pub(crate) flow_level: libc::c_int, /// The tokens queue. pub(crate) tokens: YamlQueueT, /// The number of tokens fetched from the queue. pub(crate) tokens_parsed: size_t, /// Does the tokens queue contain a token ready for dequeueing. pub(crate) token_available: bool, /// The indentation levels stack. pub(crate) indents: YamlStackT, /// The current indentation level. pub(crate) indent: libc::c_int, /// May a simple key occur at the current position? pub(crate) simple_key_allowed: bool, /// The stack of simple keys. pub(crate) simple_keys: YamlStackT, /// At least this many leading elements of simple_keys have possible=0. pub(crate) not_simple_keys: libc::c_int, /// The parser states stack. pub(crate) states: YamlStackT, /// The current parser state. pub(crate) state: YamlParserStateT, /// The stack of marks. pub(crate) marks: YamlStackT, /// The list of TAG directives. pub(crate) tag_directives: YamlStackT, /// The alias data. pub(crate) aliases: YamlStackT, /// The currently parsed document. pub(crate) document: *mut YamlDocumentT, } /// Represents the prefix data associated with a YAML parser. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlParserTPrefix { /// The error type. pub error: YamlErrorTypeT, /// The error description. pub problem: *const libc::c_char, /// The byte about which the problem occurred. pub problem_offset: size_t, /// The problematic value (-1 is none). pub problem_value: libc::c_int, /// The problem position. pub problem_mark: YamlMarkT, /// The error context. pub context: *const libc::c_char, /// The context position. pub context_mark: YamlMarkT, } #[doc(hidden)] impl Deref for YamlParserT { type Target = YamlParserTPrefix; fn deref(&self) -> &Self::Target { unsafe { &*addr_of!(*self).cast() } } } #[derive(Copy, Clone, Debug, Default)] #[repr(C)] pub(crate) struct UnnamedYamlParserTInput { /// String input data. pub(crate) string: UnnamedYamlParserTInputString, } #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct UnnamedYamlParserTInputString { /// The string start pointer. pub(crate) start: *const libc::c_uchar, /// The string end pointer. pub(crate) end: *const libc::c_uchar, /// The string current position. pub(crate) current: *const libc::c_uchar, } /// The prototype of a write handler. /// /// The write handler is called when the emitter needs to flush the accumulated /// characters to the output. The handler should write `size` bytes of the /// `buffer` to the output. /// /// On success, the handler should return 1. If the handler failed, the returned /// value should be 0. pub type YamlWriteHandlerT = unsafe fn( data: *mut libc::c_void, buffer: *mut libc::c_uchar, size: size_t, ) -> libc::c_int; /// The emitter states. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u32)] #[non_exhaustive] pub enum YamlEmitterStateT { /// Expect stream-start. YamlEmitStreamStartState = 0, /// Expect the first document-start or stream-end. YamlEmitFirstDocumentStartState = 1, /// Expect document-start or stream-end. YamlEmitDocumentStartState = 2, /// Expect the content of a document. YamlEmitDocumentContentState = 3, /// Expect document-end. YamlEmitDocumentEndState = 4, /// Expect the first item of a flow sequence. YamlEmitFlowSequenceFirstItemState = 5, /// Expect an item of a flow sequence. YamlEmitFlowSequenceItemState = 6, /// Expect the first key of a flow mapping. YamlEmitFlowMappingFirstKeyState = 7, /// Expect a key of a flow mapping. YamlEmitFlowMappingKeyState = 8, /// Expect a value for a simple key of a flow mapping. YamlEmitFlowMappingSimpleValueState = 9, /// Expect a value of a flow mapping. YamlEmitFlowMappingValueState = 10, /// Expect the first item of a block sequence. YamlEmitBlockSequenceFirstItemState = 11, /// Expect an item of a block sequence. YamlEmitBlockSequenceItemState = 12, /// Expect the first key of a block mapping. YamlEmitBlockMappingFirstKeyState = 13, /// Expect the key of a block mapping. YamlEmitBlockMappingKeyState = 14, /// Expect a value for a simple key of a block mapping. YamlEmitBlockMappingSimpleValueState = 15, /// Expect a value of a block mapping. YamlEmitBlockMappingValueState = 16, /// Expect nothing. YamlEmitEndState = 17, } #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct YamlAnchorsT { /// The number of references. pub(crate) references: libc::c_int, /// The anchor id. pub(crate) anchor: libc::c_int, /// If the node has been emitted? pub(crate) serialized: bool, } /// The emitter structure. /// /// All members are internal. Manage the structure using the `yaml_emitter_` /// family of functions. #[derive(Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlEmitterT { /// Error type. #[cfg(doc)] pub error: YamlErrorTypeT, #[cfg(not(doc))] pub(crate) error: YamlErrorTypeT, /// Error description. #[cfg(doc)] pub problem: *const libc::c_char, #[cfg(not(doc))] pub(crate) problem: *const libc::c_char, /// Write handler. pub write_handler: Option, /// A pointer for passing to the write handler. pub(crate) write_handler_data: *mut libc::c_void, /// Standard (string or file) output data. pub output: UnnamedYamlEmitterTOutput, /// The working buffer. pub buffer: YamlBufferT, /// The raw buffer. pub(crate) raw_buffer: YamlBufferT, /// The stream encoding. pub(crate) encoding: YamlEncodingT, /// If the output is in the canonical style? pub(crate) canonical: bool, /// The number of indentation spaces. pub(crate) best_indent: libc::c_int, /// The preferred width of the output lines. pub(crate) best_width: libc::c_int, /// Allow unescaped non-ASCII characters? pub(crate) unicode: bool, /// The preferred line break. pub(crate) line_break: YamlBreakT, /// The stack of states. pub(crate) states: YamlStackT, /// The current emitter state. pub(crate) state: YamlEmitterStateT, /// The event queue. pub(crate) events: YamlQueueT, /// The stack of indentation levels. pub(crate) indents: YamlStackT, /// The list of tag directives. pub(crate) tag_directives: YamlStackT, /// The current indentation level. pub(crate) indent: libc::c_int, /// The current flow level. pub(crate) flow_level: libc::c_int, /// Is it the document root context? pub(crate) root_context: bool, /// Is it a sequence context? pub(crate) sequence_context: bool, /// Is it a mapping context? pub(crate) mapping_context: bool, /// Is it a simple mapping key context? pub(crate) simple_key_context: bool, /// The current line. pub(crate) line: libc::c_int, /// The current column. pub(crate) column: libc::c_int, /// If the last character was a whitespace? pub(crate) whitespace: bool, /// If the last character was an indentation character (' ', '-', '?', ':')? pub(crate) indention: bool, /// If an explicit document end is required? pub(crate) open_ended: libc::c_int, /// Anchor analysis. pub(crate) anchor_data: UnnamedYamlEmitterTAnchorData, /// Tag analysis. pub(crate) tag_data: UnnamedYamlEmitterTTagData, /// Scalar analysis. pub(crate) scalar_data: UnnamedYamlEmitterTScalarData, /// If the stream was already opened? pub opened: bool, /// If the stream was already closed? pub closed: bool, /// The information associated with the document nodes. pub(crate) anchors: *mut YamlAnchorsT, /// The last assigned anchor id. pub(crate) last_anchor_id: libc::c_int, /// The currently emitted document. pub(crate) document: *mut YamlDocumentT, } /// Represents the prefix data associated with a YAML emitter. #[derive(Copy, Clone, Debug)] #[repr(C)] #[non_exhaustive] pub struct YamlEmitterTPrefix { /// The error type. pub error: YamlErrorTypeT, /// The error description. pub problem: *const libc::c_char, } #[doc(hidden)] impl Deref for YamlEmitterT { type Target = YamlEmitterTPrefix; fn deref(&self) -> &Self::Target { unsafe { &*addr_of!(*self).cast() } } } #[derive(Copy, Clone, Debug, Default)] #[repr(C)] /// Represents the output data associated with a YAML emitter. pub struct UnnamedYamlEmitterTOutput { /// String output data. pub string: UnnamedYamlEmitterTOutputString, } #[derive(Copy, Clone, Debug)] #[repr(C)] /// Represents the unamed output string data associated with a YAML emitter. pub struct UnnamedYamlEmitterTOutputString { /// The buffer pointer. pub buffer: *mut libc::c_uchar, /// The buffer size. pub size: size_t, /// The number of written bytes. pub size_written: *mut size_t, } #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct UnnamedYamlEmitterTAnchorData { /// The anchor value. pub(crate) anchor: *mut yaml_char_t, /// The anchor length. pub(crate) anchor_length: size_t, /// Is it an alias? pub(crate) alias: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub(crate) struct UnnamedYamlEmitterTTagData { /// The tag handle. pub(crate) handle: *mut yaml_char_t, /// The tag handle length. pub(crate) handle_length: size_t, /// The tag suffix. pub(crate) suffix: *mut yaml_char_t, /// The tag suffix length. pub(crate) suffix_length: size_t, } #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct UnnamedYamlEmitterTScalarData { /// The scalar value. pub(crate) value: *mut yaml_char_t, /// The scalar length. pub(crate) length: size_t, /// Does the scalar contain line breaks? pub(crate) multiline: bool, /// Can the scalar be expressed in the flow plain style? pub(crate) flow_plain_allowed: bool, /// Can the scalar be expressed in the block plain style? pub(crate) block_plain_allowed: bool, /// Can the scalar be expressed in the single quoted style? pub(crate) single_quoted_allowed: bool, /// Can the scalar be expressed in the literal or folded styles? pub(crate) block_allowed: bool, /// The output style. pub(crate) style: YamlScalarStyleT, } #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct YamlStringT { pub(crate) start: *mut yaml_char_t, pub(crate) end: *mut yaml_char_t, pub(crate) pointer: *mut yaml_char_t, } pub(crate) const NULL_STRING: YamlStringT = YamlStringT { start: ptr::null_mut::(), end: ptr::null_mut::(), pointer: ptr::null_mut::(), }; #[derive(Copy, Clone, Debug)] #[repr(C)] /// Represents the data associated with a YAML token. pub struct YamlBufferT { /// The beginning of the buffer. pub start: *mut T, /// The end of the buffer. pub end: *mut T, /// The current position of the buffer. pub pointer: *mut T, /// The last filled position of the buffer. pub last: *mut T, } impl YamlBufferT { /// Is the buffer empty? pub(crate) fn is_empty(&self) -> bool { self.pointer == self.last } /// Advances the buffer by one character. pub(crate) fn next(&mut self) { if !self.is_empty() { unsafe { self.pointer = self.pointer.add(1); } } } } impl Default for YamlBufferT { fn default() -> Self { YamlBufferT { start: ptr::null_mut(), end: ptr::null_mut(), pointer: ptr::null_mut(), last: ptr::null_mut(), } } } /// The beginning of the stack. #[derive(Debug)] #[repr(C)] pub struct YamlStackT { /// The beginning of the stack. pub start: *mut T, /// The end of the stack. pub end: *mut T, /// The top of the stack. pub top: *mut T, } impl Copy for YamlStackT {} impl Clone for YamlStackT { fn clone(&self) -> Self { *self } } /// The beginning of the queue. #[derive(Debug)] #[repr(C)] pub(crate) struct YamlQueueT { /// The beginning of the queue. pub(crate) start: *mut T, /// The end of the queue. pub(crate) end: *mut T, /// The head of the queue. pub(crate) head: *mut T, /// The tail of the queue. pub(crate) tail: *mut T, } impl Copy for YamlQueueT {} impl Clone for YamlQueueT { fn clone(&self) -> Self { *self } } impl Default for YamlQueueT { fn default() -> Self { YamlQueueT { start: ptr::null_mut(), end: ptr::null_mut(), head: ptr::null_mut(), tail: ptr::null_mut(), } } } impl Default for YamlStringT { fn default() -> Self { YamlStringT { start: ptr::null_mut(), end: ptr::null_mut(), pointer: ptr::null_mut(), } } } impl Default for UnnamedYamlEmitterTScalarData { fn default() -> Self { UnnamedYamlEmitterTScalarData { value: ptr::null_mut(), length: 0, multiline: false, flow_plain_allowed: false, block_plain_allowed: false, single_quoted_allowed: false, block_allowed: false, style: YamlScalarStyleT::YamlAnyScalarStyle, } } } impl Default for UnnamedYamlEmitterTTagData { fn default() -> Self { UnnamedYamlEmitterTTagData { handle: ptr::null_mut(), handle_length: 0, suffix: ptr::null_mut(), suffix_length: 0, } } } impl Default for UnnamedYamlEmitterTAnchorData { fn default() -> Self { UnnamedYamlEmitterTAnchorData { anchor: ptr::null_mut(), anchor_length: 0, alias: false, } } } impl Default for UnnamedYamlEmitterTOutputString { fn default() -> Self { UnnamedYamlEmitterTOutputString { buffer: ptr::null_mut(), size: 0, size_written: ptr::null_mut(), } } } impl Default for UnnamedYamlParserTInputString { fn default() -> Self { UnnamedYamlParserTInputString { start: ptr::null(), end: ptr::null(), current: ptr::null(), } } } impl Default for UnnamedYamlDocumentTTagDirectives { fn default() -> Self { UnnamedYamlDocumentTTagDirectives { start: ptr::null_mut(), end: ptr::null_mut(), } } } impl Default for YamlEncodingT { fn default() -> Self { YamlAnyEncoding } } impl Default for YamlParserStateT { fn default() -> Self { YamlParserStateT::YamlParseStreamStartState } } impl Default for YamlScalarStyleT { fn default() -> Self { YamlScalarStyleT::YamlAnyScalarStyle } } impl Default for YamlTokenT { fn default() -> Self { YamlTokenT { type_: YamlTokenTypeT::YamlNoToken, data: UnnamedYamlTokenTData::default(), start_mark: YamlMarkT::default(), end_mark: YamlMarkT::default(), } } } impl Default for UnnamedYamlTokenTdataStreamStart { fn default() -> Self { UnnamedYamlTokenTdataStreamStart { encoding: YamlAnyEncoding, } } } impl Default for UnnamedYamlTokenTdataAlias { fn default() -> Self { UnnamedYamlTokenTdataAlias { value: ptr::null_mut(), } } } impl Default for UnnamedYamlTokenTdataAnchor { fn default() -> Self { UnnamedYamlTokenTdataAnchor { value: ptr::null_mut(), } } } impl Default for UnnamedYamlTokenTdataTag { fn default() -> Self { UnnamedYamlTokenTdataTag { handle: ptr::null_mut(), suffix: ptr::null_mut(), } } } impl Default for UnnamedYamlTokenTdataScalar { fn default() -> Self { UnnamedYamlTokenTdataScalar { value: ptr::null_mut(), length: 0, style: YamlScalarStyleT::YamlAnyScalarStyle, } } } impl Default for UnnamedYamlTokenTdataTagDirective { fn default() -> Self { UnnamedYamlTokenTdataTagDirective { handle: ptr::null_mut(), prefix: ptr::null_mut(), } } } impl Default for YamlStackT { fn default() -> Self { YamlStackT { start: ptr::null_mut(), end: ptr::null_mut(), top: ptr::null_mut(), } } } impl Default for YamlStackT { fn default() -> Self { YamlStackT { start: ptr::null_mut(), end: ptr::null_mut(), top: ptr::null_mut(), } } } impl Default for YamlStackT { fn default() -> Self { YamlStackT { start: ptr::null_mut(), end: ptr::null_mut(), top: ptr::null_mut(), } } } impl Default for YamlTagDirectiveT { fn default() -> Self { YamlTagDirectiveT { handle: ptr::null_mut(), prefix: ptr::null_mut(), } } } impl Default for YamlBreakT { fn default() -> Self { YamlBreakT::YamlAnyBreak } } impl Default for YamlSequenceStyleT { fn default() -> Self { YamlSequenceStyleT::YamlAnySequenceStyle } } impl Default for YamlMappingStyleT { fn default() -> Self { YamlMappingStyleT::YamlAnyMappingStyle } } impl Default for YamlEventTypeT { fn default() -> Self { YamlNoEvent } } impl Default for YamlAliasDataT { fn default() -> Self { YamlAliasDataT { anchor: ptr::null_mut(), index: 0, mark: YamlMarkT::default(), } } } impl Default for YamlNodeTypeT { fn default() -> Self { YamlNoNode } } impl Default for YamlEmitterStateT { fn default() -> Self { YamlEmitterStateT::YamlEmitStreamStartState } } impl YamlDocumentT { /// Cleans up resources used by `YamlDocumentT`. This includes deallocating memory for /// version directives, tag directives, and nodes if they were allocated dynamically. /// /// # Safety /// /// This function is `unsafe` because it assumes that all pointers (e.g., version_directive, /// tag directives, and nodes) are either valid or null. It will attempt to free allocated /// memory, so the caller must ensure that: /// /// 1. The struct has been initialized properly. /// 2. No other code retains pointers to the data being freed here. /// 3. This method is not called concurrently with any operations that read from or write to /// the pointed-to data. /// 4. The memory management strategy (allocation and deallocation) is correctly paired. /// For instance, if `libc::malloc` is used to allocate, `libc::free` should be used to deallocate. /// pub unsafe fn cleanup(&mut self) { // Assuming `version_directive` and `tag_directives.start/end` are pointers that need to be freed. if !self.version_directive.is_null() { // Free version_directive if your logic requires it, e.g., // libc::free(self.version_directive as *mut libc::c_void); self.version_directive = ptr::null_mut(); } // Example of cleaning up tag directives if they were allocated dynamically let mut tag_directive = self.tag_directives.start; while tag_directive < self.tag_directives.end { // Free each tag directive if necessary // libc::free((*tag_directive).handle as *mut libc::c_void); // libc::free((*tag_directive).prefix as *mut libc::c_void); tag_directive = tag_directive.offset(1); } // Assuming `nodes` needs to be cleaned up let mut node = self.nodes.start; while node < self.nodes.top { // Free each node if necessary // libc::free((*node).tag as *mut libc::c_void); node = node.offset(1); } // Free the nodes array itself if it was dynamically allocated // libc::free(self.nodes.start as *mut libc::c_void); self.nodes.start = ptr::null_mut(); self.nodes.end = ptr::null_mut(); self.nodes.top = ptr::null_mut(); } } impl Default for YamlDocumentT { fn default() -> Self { YamlDocumentT { nodes: YamlStackT { start: ptr::null_mut(), end: ptr::null_mut(), top: ptr::null_mut(), }, version_directive: ptr::null_mut(), tag_directives: UnnamedYamlDocumentTTagDirectives::default( ), start_implicit: false, end_implicit: false, start_mark: YamlMarkT::default(), end_mark: YamlMarkT::default(), } } } libyml-0.0.5/tests/bin/mod.rs000064400000000000000000000032601046102023000141560ustar 00000000000000use std::error::Error; use std::fmt; use std::fs::File; use std::io::{Read, Write}; use std::path::Path; use std::process::{Command, Stdio}; // Define a custom error type #[derive(Debug)] pub(crate) enum MyError { IoError(std::io::Error), Other(String), } impl fmt::Display for MyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MyError::IoError(e) => write!(f, "I/O Error: {}", e), MyError::Other(s) => write!(f, "Error: {}", s), } } } impl Error for MyError {} impl From for MyError { fn from(error: std::io::Error) -> Self { MyError::IoError(error) } } pub(crate) struct Output { pub(crate) success: bool, pub(crate) stdout: Vec, pub(crate) stderr: Vec, } pub(crate) fn run( compiled: &str, unsafe_main: unsafe fn( stdin: &mut dyn Read, stdout: &mut dyn Write, ) -> Result<(), MyError>, input: &Path, ) -> Output { if cfg!(miri) { let mut input = File::open(input).unwrap(); let mut stdout = Vec::new(); let result = unsafe { unsafe_main(&mut input, &mut stdout) }; Output { success: result.is_ok(), stdout, stderr: match result { Ok(_) => Vec::new(), Err(e) => e.to_string().into_bytes(), }, } } else { let output = Command::new(compiled) .arg(input) .stdin(Stdio::null()) .output() .unwrap(); Output { success: output.status.success(), stdout: output.stdout, stderr: output.stderr, } } } libyml-0.0.5/tests/explicit_types.yaml000064400000000000000000000000711046102023000162070ustar 00000000000000integer: !!int 42 float: !!float 3.14 string: !!str valuelibyml-0.0.5/tests/ignorelist/libyaml-emitter000064400000000000000000000060271046102023000174670ustar 0000000000000026DV: Whitespace around colon in mappings 2EBW: Allowed characters in keys 2JQS: Block Mapping with Missing Keys 2LFX: Spec Example 6.13. Reserved Directives [1.3] 2SXE: Anchors With Colon in Name 2XXW: Spec Example 2.25. Unordered Sets 3MYT: Plain Scalar looking like key, comment, anchor and tag 4ABK: Spec Example 7.17. Flow Mapping Separate Values 4MUZ: Flow mapping colon on line after key 4QFQ: Spec Example 8.2. Block Indentation Indicator [1.3] 52DL: Explicit Non-Specific Tag [1.3] 565N: Construct Binary 5TYM: Spec Example 6.21. Local Tag Prefix 5WE3: Spec Example 8.17. Explicit Block Mapping Entries 6CK3: Spec Example 6.26. Tag Shorthands 6FWR: Block Scalar Keep 6KGN: Anchor for empty node 6M2F: Aliases in Explicit Block Mapping 6PBE: Zero-indented sequences in explicit mapping keys 6SLA: Allowed characters in quoted mapping key 6WLZ: Spec Example 6.18. Primary Tag Handle [1.3] 6WPF: Spec Example 6.8. Flow Folding [1.3] 6XDY: Two document start markers 6ZKB: Spec Example 9.6. Stream 7T8X: Spec Example 8.10. Folded Lines - 8.13. Final Empty Lines 7W2P: Block Mapping with Missing Values 7Z25: Bare document after document end marker 8KB6: Multiline plain flow mapping key without value 8XYN: Anchor with unicode character 9BXH: Multiline doublequoted flow mapping key without value 8MK2: Explicit Non-Specific Tag 9DXL: Spec Example 9.6. Stream [1.3] 9MMW: Spec Example 7.21. Single Pair Implicit Entries [1.3 9TFX: Spec Example 7.6. Double Quoted Lines [1.3] B3HG: Spec Example 8.9. Folded Scalar [1.3] C2DT: Spec Example 7.18. Flow Mapping Adjacent Values DFF7: Spec Example 7.16. Flow Mapping Entries E76Z: Aliases in Implicit Block Mapping EX5H: Multiline Scalar at Top Level [1.3] EXG3: Three dashes and content without space [1.3] FBC9: Allowed characters in plain scalars FH7J: Tags on Empty Scalars FRK4: Spec Example 7.3. Completely Empty Flow Nodes J3BT: Spec Example 5.12. Tabs and Spaces JDH8: Plain Scalar looking like key, comment, anchor and tag [1.3] JTV5: Block Mapping with Multiline Scalars K54U: Tab after document header KK5P: Various combinations of explicit block mappings KSS4: Scalars on --- line KZN9: Spec Example 7.21. Single Pair Implicit Entries LE5A: Spec Example 7.24. Flow Nodes M7A3: Spec Example 9.3. Bare Documents M9B4: Spec Example 8.7. Literal Scalar NAT4: Various empty or newline only quoted strings NHX8: Empty Lines at End of Document PUW8: Document start on last line PW8X: Anchors on Empty Scalars Q8AD: Spec Example 7.5. Double Quoted Line Breaks [1.3] S3PD: Spec Example 8.18. Implicit Block Mapping Entries S4JQ: Spec Example 6.28. Non-Specific Tags T26H: Spec Example 8.8. Literal Content [1.3] T4YY: Spec Example 7.9. Single Quoted Lines [1.3] T5N4: Spec Example 8.7. Literal Scalar [1.3] UT92: Spec Example 9.4. Explicit Documents W42U: Spec Example 8.15. Block Sequence Entry Types W4TN: Spec Example 9.5. Directives Documents W5VH: Allowed characters in alias WZ62: Spec Example 7.2. Empty Content X38W: Aliases in Flow Objects XLQ9: Multiline scalar that looks like a YAML directive Y2GN: Anchor with colon in the middle libyml-0.0.5/tests/ignorelist/libyaml-parser000064400000000000000000000027611046102023000173130ustar 000000000000002JQS: Block Mapping with Missing Keys 2LFX: Spec Example 6.13. Reserved Directives [1.3] 2SXE: Anchors With Colon in Name 4ABK: Spec Example 7.17. Flow Mapping Separate Values 4MUZ: Flow mapping colon on line after key 5MUD: Colon and adjacent value on next line 6BCT: Spec Example 6.3. Separation Spaces 6LVF: Spec Example 6.13. Reserved Directives 6M2F: Aliases in Explicit Block Mapping 7Z25: Bare document after document end marker 8XYN: Anchor with unicode character 9MMW: Spec Example 7.21. Single Pair Implicit Entries [1.3 9SA2: Multiline double quoted flow mapping key A2M4: Spec Example 6.2. Indentation Indicators BEC7: Spec Example 6.14. “YAML” directive DBG4: Spec Example 7.10. Plain Characters DK3J: Zero indented block scalar with line that looks like a comment FP8R: Zero indented block scalar FRK4: Spec Example 7.3. Completely Empty Flow Nodes HWV9: Document-end marker K3WX: Colon and adjacent value after comment on next line KZN9: Spec Example 7.21. Single Pair Implicit Entries M7A3: Spec Example 9.3. Bare Documents NHX8: Empty Lines at End of Document NJ66: Multiline plain flow mapping key Q5MG: Tab at beginning of line followed by a flow mapping QT73: Comment and document-end marker R4YG: Spec Example 8.2. Block Indentation Indicator S3PD: Spec Example 8.18. Implicit Block Mapping Entries UT92: Spec Example 9.4. Explicit Documents W4TN: Spec Example 9.5. Directives Documents W5VH: Allowed characters in alias WZ62: Spec Example 7.2. Empty Content Y2GN: Anchor with colon in the middlelibyml-0.0.5/tests/ignorelist/libyaml-parser-error000064400000000000000000000007511046102023000204370ustar 000000000000009C9N: Wrong indented flow sequence 9HCY: Need document footer before directives 9JBA: Invalid comment after end of flow sequence CVW2: Invalid comment after comma EB22: Missing document-end marker before directive QB6E: Wrong indented multiline quoted scalar RHX7: YAML directive without document end marker S98Z: Block scalar with more spaces than first content line SU5Z: Comment without whitespace after doublequoted scalar X4QW: Comment without whitespace after block scalar indicator libyml-0.0.5/tests/invalid_anchor.yaml000064400000000000000000000001501046102023000161200ustar 00000000000000 anchor1: &a1 value1 anchor2: &a2 value2 invalid_alias: *a3 # This alias doesn't exist libyml-0.0.5/tests/test_api.rs000064400000000000000000000040311046102023000144340ustar 00000000000000#[cfg(test)] mod tests { use core::ffi::c_void; use libyml::externs::free; use libyml::memory::yaml_malloc; use libyml::memory::yaml_strdup; use std::ptr::null; use std::ptr::null_mut; #[test] fn test_yaml_malloc() { unsafe { // Test allocation of zero bytes let ptr = yaml_malloc(0); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory // Test allocation of non-zero bytes let ptr = yaml_malloc(10); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory } } #[test] fn test_yaml_malloc_free() { unsafe { // Test allocation of zero bytes let ptr = yaml_malloc(0); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory // Test allocation of non-zero bytes let ptr = yaml_malloc(10); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory } } #[test] fn test_yaml_realloc() { unsafe { // Test allocation of zero bytes let ptr = yaml_malloc(0); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory // Test allocation of non-zero bytes let ptr = yaml_malloc(10); assert!(!ptr.is_null()); yaml_free(ptr); // Ensure to free the allocated memory } } #[test] fn test_yaml_free() { unsafe { // Test freeing null pointer let ptr = yaml_malloc(0); yaml_free(ptr); } } #[test] fn test_yaml_strdup() { unsafe { // Test duplication of a null string let ptr = yaml_strdup(null()); assert_eq!(ptr, null_mut()); } } // Helper function to free memory unsafe fn yaml_free(ptr: *mut c_void) { free(ptr); } } libyml-0.0.5/tests/test_decode.rs000064400000000000000000000146161046102023000151200ustar 00000000000000#[cfg(test)] mod tests { use core::mem::MaybeUninit; use libyml::decode::yaml_parser_delete; use libyml::decode::yaml_parser_initialize; use libyml::YamlParserT; /// Tests the basic initialization of a YAML parser. /// /// This test ensures that the `yaml_parser_initialize` function /// successfully initializes a `YamlParserT` struct and returns /// a successful result. /// /// # Safety /// /// This test uses unsafe code to work with raw pointers. #[test] fn test_yaml_parser_initialize() { unsafe { let mut parser = MaybeUninit::::uninit(); let result = yaml_parser_initialize(parser.as_mut_ptr()); assert!(result.ok, "Parser initialization should succeed"); } } /// Tests both initialization and deletion of a YAML parser. /// /// This test verifies that a parser can be successfully initialized /// and then deleted without any errors. /// /// # Safety /// /// This test uses unsafe code to work with raw pointers and to call /// functions that require manual memory management. #[test] fn test_yaml_parser_initialize_and_delete() { unsafe { let mut parser = MaybeUninit::::uninit(); let init_result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( init_result.ok, "Parser initialization should succeed" ); let parser_ptr = parser.as_mut_ptr(); yaml_parser_delete(parser_ptr); // Note: We can't test the state after deletion as it would be undefined behavior } } /// Tests multiple initializations and deletions of YAML parsers. /// /// This test ensures that multiple parsers can be initialized and /// deleted in succession without any errors, verifying the robustness /// of the initialization and deletion processes. /// /// # Safety /// /// This test uses unsafe code to work with raw pointers and to call /// functions that require manual memory management. #[test] fn test_multiple_initialize_and_delete() { unsafe { for i in 0..5 { let mut parser = MaybeUninit::::uninit(); let init_result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( init_result.ok, "Parser initialization should succeed on iteration {}", i ); let parser_ptr = parser.as_mut_ptr(); yaml_parser_delete(parser_ptr); } } } /// Tests the overall functionality of parser initialization and deletion. /// /// # Safety /// /// This test uses unsafe code to initialize and delete the parser. #[test] fn test_parser_initialization_and_deletion() { unsafe { let mut parser = MaybeUninit::::uninit(); let init_result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( init_result.ok, "Parser initialization should succeed" ); // We can't directly test private fields, but we can ensure that // initialization and deletion don't cause any crashes or panics yaml_parser_delete(parser.as_mut_ptr()); } } /// Tests that using a deleted parser doesn't cause undefined behavior. /// /// # Safety /// /// This test uses unsafe code to initialize, delete, and re-initialize the parser. #[test] fn test_parser_after_deletion() { unsafe { let mut parser = MaybeUninit::::uninit(); let _ = yaml_parser_initialize(parser.as_mut_ptr()); let parser_ptr = parser.as_mut_ptr(); yaml_parser_delete(parser_ptr); // After deletion, re-initializing should still work without issues let reinit_result = yaml_parser_initialize(parser_ptr); assert!( reinit_result.ok, "Parser re-initialization after deletion should succeed" ); yaml_parser_delete(parser_ptr); } } /// Tests that calling delete multiple times doesn't cause issues. /// /// # Safety /// /// This test uses unsafe code to initialize and delete the parser multiple times. #[test] fn test_multiple_deletions() { unsafe { let mut parser = MaybeUninit::::uninit(); let init_result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( init_result.ok, "Parser initialization should succeed" ); let parser_ptr = parser.as_mut_ptr(); yaml_parser_delete(parser_ptr); // We'll remove the second deletion as it's not safe to delete an already deleted parser } } /// Tests for potential memory leaks during initialization and deletion. /// /// Note: This test is a placeholder and doesn't actually track allocations. /// /// # Safety /// /// This test uses unsafe code to initialize and delete the parser. #[test] fn test_memory_leaks() { unsafe { // We can't track allocations without a custom allocator, so we'll just // test that we can initialize and delete without crashing let mut parser = MaybeUninit::::uninit(); let init_result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( init_result.ok, "Parser initialization should succeed" ); yaml_parser_delete(parser.as_mut_ptr()); } } /// Tests that initializing with a valid pointer succeeds. /// /// # Safety /// /// This test uses unsafe code to initialize the parser. #[test] fn test_yaml_parser_initialize_valid() { unsafe { let mut parser = MaybeUninit::::uninit(); let result = yaml_parser_initialize(parser.as_mut_ptr()); assert!( result.ok, "Parser initialization should succeed with valid pointer" ); // Clean up yaml_parser_delete(parser.as_mut_ptr()); } } } libyml-0.0.5/tests/test_document.rs000064400000000000000000000727251046102023000155200ustar 00000000000000#[cfg(test)] mod tests { use core::mem::MaybeUninit; use libyml::{ document::{ yaml_document_add_mapping, yaml_document_add_scalar, yaml_document_add_sequence, yaml_document_append_mapping_pair, yaml_document_append_sequence_item, yaml_document_end_event_initialize, yaml_document_start_event_initialize, }, success::{FAIL, OK}, yaml_document_delete, yaml_document_get_node, yaml_document_get_root_node, yaml_document_initialize, YamlDocumentT, YamlEventT, YamlEventTypeT::{ YamlDocumentEndEvent, YamlDocumentStartEvent, }, YamlMappingStyleT, YamlNodeTypeT::YamlScalarNode, YamlScalarStyleT, YamlSequenceStyleT, YamlTagDirectiveT, YamlVersionDirectiveT, }; use std::ptr; // Document Initialization Tests #[test] /// Test basic document initialization with null pointers fn test_yaml_document_initialize_non_null_document() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( result, OK, "Initialization should handle null pointers gracefully" ); doc.cleanup(); } } #[test] /// Test document initialization with a version directive fn test_yaml_document_initialize_with_version_directive() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let mut version_directive = YamlVersionDirectiveT::new(1, 2); let version_directive_ptr: *mut YamlVersionDirectiveT = &mut version_directive; let result = yaml_document_initialize( &mut doc, version_directive_ptr, ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( result, OK, "Initialization with version directive failed" ); doc.cleanup(); } } #[test] /// Test document initialization fn test_yaml_document_initialize() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert!( result.ok, "Document initialization should succeed with valid pointer" ); } } #[test] /// Test document initialization with version directive fn test_yaml_document_initialize_valid() { unsafe { let mut doc: MaybeUninit = MaybeUninit::uninit(); let mut version_directive = YamlVersionDirectiveT::new(1, 2); let mut tag_directives = vec![]; let version_directive_ptr: *mut YamlVersionDirectiveT = &mut version_directive; let result = yaml_document_initialize( doc.as_mut_ptr(), version_directive_ptr, tag_directives.as_mut_ptr(), tag_directives.as_mut_ptr().add(tag_directives.len()), true, false, ); assert_eq!( result, OK, "Initialization should succeed with valid inputs" ); yaml_document_delete(doc.as_mut_ptr()); } } #[test] /// Test document initialization with invalid pointers fn test_yaml_document_initialize_invalid() { unsafe { let mut doc: MaybeUninit = MaybeUninit::uninit(); let result = yaml_document_initialize( doc.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( result, OK, "Initialization should handle null pointers gracefully" ); yaml_document_delete(doc.as_mut_ptr()); } } #[test] /// Test document initialization with implicit document fn test_yaml_document_initialize_implicit_document() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), true, // Implicit false, ); assert_eq!( result, OK, "Initialization should succeed with implicit document" ); doc.cleanup(); } } #[test] /// Test document initialization with explicit document fn test_yaml_document_initialize_explicit_document() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, // Explicit true, ); assert_eq!( result, OK, "Initialization should succeed with explicit document" ); doc.cleanup(); } } #[test] /// Test document initialization with mixed flags fn test_yaml_document_initialize_mixed_flags() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), true, // Implicit true, // Explicit ); assert_eq!( result, OK, "Initialization should handle mixed implicit and explicit flags" ); doc.cleanup(); } } // Tag Directive Tests #[test] /// Test document initialization with non-empty tag directives fn test_yaml_document_initialize_with_non_empty_tag_directives() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let mut tag_directive: YamlTagDirectiveT = MaybeUninit::zeroed().assume_init(); tag_directive.handle = b"!my_tag!\0".as_ptr() as *mut u8; tag_directive.prefix = b"tag:yaml.org,2002:\0".as_ptr() as *mut u8; let tag_directive_start: *mut YamlTagDirectiveT = &mut tag_directive; let tag_directive_end: *mut YamlTagDirectiveT = tag_directive_start.wrapping_offset(1); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), tag_directive_start, tag_directive_end, false, false, ); assert_eq!( result, OK, "Initialization with non-empty tag directives failed" ); doc.cleanup(); } } #[test] /// Test document initialization with invalid UTF-8 in tag directive fn test_yaml_document_initialize_with_invalid_utf8_tag_directive() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let mut tag_directive: YamlTagDirectiveT = MaybeUninit::zeroed().assume_init(); // Invalid UTF-8 sequence (incomplete multibyte sequence) tag_directive.handle = b"invalid\xFF\0".as_ptr() as *mut u8; tag_directive.prefix = b"tag:yaml.org,2002:\0".as_ptr() as *mut u8; let tag_directive_start: *mut YamlTagDirectiveT = &mut tag_directive; let tag_directive_end: *mut YamlTagDirectiveT = tag_directive_start.wrapping_offset(1); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), tag_directive_start, tag_directive_end, false, false, ); assert_eq!( result, FAIL, "Initialization should fail with invalid UTF-8 in tag directive" ); } } #[test] /// Test document initialization with null tag directives fn test_yaml_document_initialize_with_null_tag_directives() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( result, OK, "Initialization should succeed with null tag directives" ); doc.cleanup(); } } #[test] /// Test document initialization with large tag directives fn test_yaml_document_initialize_large_tag_directives() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let mut large_tag_directive: YamlTagDirectiveT = MaybeUninit::zeroed().assume_init(); // Allocate large arrays directly on the stack let large_handle = [b'a'; 1024]; // 1KB handle let large_prefix = [b'b'; 1024]; // 1KB prefix large_tag_directive.handle = large_handle.as_ptr() as *mut u8; large_tag_directive.prefix = large_prefix.as_ptr() as *mut u8; let tag_directive_start: *mut YamlTagDirectiveT = &mut large_tag_directive; let tag_directive_end: *mut YamlTagDirectiveT = tag_directive_start.wrapping_offset(1); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), tag_directive_start, tag_directive_end, false, false, ); assert_eq!( result, OK, "Initialization with large tag directives failed" ); doc.cleanup(); } } // Document Deletion Tests #[test] /// Test document deletion fn test_yaml_document_delete() { unsafe { let mut doc: MaybeUninit = MaybeUninit::zeroed(); let doc_ptr = doc.as_mut_ptr(); let init_result = yaml_document_initialize( doc_ptr, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert!( init_result == OK, "Document initialization should succeed with valid pointer" ); let doc = doc_ptr.as_mut().unwrap(); doc.cleanup(); } } #[test] /// Test document deletion with null pointer fn test_yaml_document_delete_null() { unsafe { yaml_document_delete(ptr::null_mut()); } } #[test] /// Test document deletion with already deleted document fn test_yaml_document_delete_already_deleted_document() { unsafe { let mut doc: MaybeUninit = MaybeUninit::zeroed(); let doc_ptr = doc.as_mut_ptr(); let init_result = yaml_document_initialize( doc_ptr, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( init_result, OK, "Document initialization failed" ); yaml_document_delete(doc_ptr); // First deletion yaml_document_delete(doc_ptr); // Second deletion, should handle gracefully } } // Other Tests #[test] /// Test document cleanup fn test_yaml_document_cleanup() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!(result, OK, "Initialization failed"); doc.cleanup(); } } #[test] /// Test memory allocation failure fn test_memory_allocation_failure() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); // Assert that the function returns the expected result if result == FAIL { // If the initialization failed, ensure that it was handled assert_eq!( result, FAIL, "Expected memory allocation to fail, and it did." ); } else { // If the initialization succeeded, assert success and perform cleanup assert_eq!( result, OK, "Expected memory allocation to succeed, and it did." ); doc.cleanup(); // Ensure proper cleanup } } } #[test] /// Test document initialization with different node types fn test_yaml_document_initialize_with_different_node_types() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!(result, OK, "Document initialization failed"); doc.cleanup(); } } #[test] /// Test initialization with empty nodes fn test_yaml_document_with_empty_nodes() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!(result, OK, "Document initialization failed"); // Add an empty scalar node let scalar_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"".as_ptr(), 0, YamlScalarStyleT::YamlPlainScalarStyle, ); assert!(scalar_id > 0, "Failed to add empty scalar node"); // Add an empty sequence node let sequence_id = yaml_document_add_sequence( &mut doc, ptr::null(), YamlSequenceStyleT::YamlBlockSequenceStyle, ); assert!( sequence_id > 0, "Failed to add empty sequence node" ); // Add an empty mapping node let mapping_id = yaml_document_add_mapping( &mut doc, ptr::null(), YamlMappingStyleT::YamlBlockMappingStyle, ); assert!(mapping_id > 0, "Failed to add empty mapping node"); // Verify that we can retrieve the nodes let scalar_node = yaml_document_get_node(&mut doc, scalar_id); assert!( !scalar_node.is_null(), "Failed to retrieve scalar node" ); let sequence_node = yaml_document_get_node(&mut doc, sequence_id); assert!( !sequence_node.is_null(), "Failed to retrieve sequence node" ); let mapping_node = yaml_document_get_node(&mut doc, mapping_id); assert!( !mapping_node.is_null(), "Failed to retrieve mapping node" ); doc.cleanup(); } } #[test] /// Test repeated initialization and deletion of documents fn test_yaml_document_multiple_initialization_deletion() { unsafe { for _ in 0..100 { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( result, OK, "Document initialization failed" ); yaml_document_delete(&mut doc); } } } #[test] /// Test getting the root node of a document fn test_yaml_document_get_root_node() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let _ = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); let node_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"root\0".as_ptr(), 4, YamlScalarStyleT::YamlPlainScalarStyle, ); assert!(node_id > 0, "Failed to add root node"); let root_node = yaml_document_get_root_node(&mut doc); assert!(!root_node.is_null(), "Failed to get root node"); assert_eq!( (*root_node).type_, YamlScalarNode, "Root node is not a scalar" ); doc.cleanup(); } } #[test] /// Test appending items to a sequence fn test_yaml_document_append_sequence_item() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let _ = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); let seq_id = yaml_document_add_sequence( &mut doc, ptr::null(), YamlSequenceStyleT::YamlBlockSequenceStyle, ); assert!(seq_id > 0, "Failed to add sequence"); let item1_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"item1\0".as_ptr(), 5, YamlScalarStyleT::YamlPlainScalarStyle, ); let item2_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"item2\0".as_ptr(), 5, YamlScalarStyleT::YamlPlainScalarStyle, ); assert_eq!( yaml_document_append_sequence_item( &mut doc, seq_id, item1_id ), OK ); assert_eq!( yaml_document_append_sequence_item( &mut doc, seq_id, item2_id ), OK ); let seq_node = yaml_document_get_node(&mut doc, seq_id); assert!(!seq_node.is_null(), "Failed to get sequence node"); assert_eq!( (*seq_node) .data .sequence .items .top .offset_from((*seq_node).data.sequence.items.start), 2, "Sequence should have 2 items" ); doc.cleanup(); } } #[test] /// Test adding pairs to a mapping fn test_yaml_document_append_mapping_pair() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let _ = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); let map_id = yaml_document_add_mapping( &mut doc, ptr::null(), YamlMappingStyleT::YamlBlockMappingStyle, ); assert!(map_id > 0, "Failed to add mapping"); let key1_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"key1\0".as_ptr(), 4, YamlScalarStyleT::YamlPlainScalarStyle, ); let value1_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"value1\0".as_ptr(), 6, YamlScalarStyleT::YamlPlainScalarStyle, ); let key2_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"key2\0".as_ptr(), 4, YamlScalarStyleT::YamlPlainScalarStyle, ); let value2_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"value2\0".as_ptr(), 6, YamlScalarStyleT::YamlPlainScalarStyle, ); assert_eq!( yaml_document_append_mapping_pair( &mut doc, map_id, key1_id, value1_id ), OK ); assert_eq!( yaml_document_append_mapping_pair( &mut doc, map_id, key2_id, value2_id ), OK ); let map_node = yaml_document_get_node(&mut doc, map_id); assert!(!map_node.is_null(), "Failed to get mapping node"); assert_eq!( (*map_node) .data .mapping .pairs .top .offset_from((*map_node).data.mapping.pairs.start), 2, "Mapping should have 2 pairs" ); doc.cleanup(); } } #[test] /// Test document end event initialization fn test_yaml_document_end_event_initialize() { unsafe { let mut event: YamlEventT = MaybeUninit::zeroed().assume_init(); assert_eq!( yaml_document_end_event_initialize(&mut event, true), OK ); assert_eq!(event.type_, YamlDocumentEndEvent); assert!(event.data.document_end.implicit); } } #[test] /// Test document start event initialization fn test_yaml_document_start_event_initialize() { unsafe { let mut event: YamlEventT = MaybeUninit::zeroed().assume_init(); let mut version_directive = YamlVersionDirectiveT::new(1, 1); assert_eq!( yaml_document_start_event_initialize( &mut event, &mut version_directive, ptr::null_mut(), ptr::null_mut(), true ), OK ); assert_eq!(event.type_, YamlDocumentStartEvent); assert!(event.data.document_start.implicit); assert!(!event .data .document_start .version_directive .is_null()); assert_eq!( (*event.data.document_start.version_directive).major, 1 ); assert_eq!( (*event.data.document_start.version_directive).minor, 1 ); } } #[test] /// Test adding scalar nodes to a document fn test_yaml_document_add_scalar() { unsafe { let mut doc: YamlDocumentT = MaybeUninit::zeroed().assume_init(); let init_result = yaml_document_initialize( &mut doc, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), false, false, ); assert_eq!( init_result, OK, "Document initialization failed" ); // Test adding an empty scalar let empty_scalar_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"".as_ptr(), 0, YamlScalarStyleT::YamlPlainScalarStyle, ); assert!( empty_scalar_id > 0, "Failed to add empty scalar node" ); // Test adding a non-empty scalar let non_empty_scalar_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"Hello, World!\0".as_ptr(), 13, YamlScalarStyleT::YamlPlainScalarStyle, ); assert!( non_empty_scalar_id > 0, "Failed to add non-empty scalar node" ); // Test adding a scalar with a custom tag let custom_tag = b"!custom\0".as_ptr(); let custom_tag_scalar_id = yaml_document_add_scalar( &mut doc, custom_tag, b"Custom tagged scalar\0".as_ptr(), 20, YamlScalarStyleT::YamlSingleQuotedScalarStyle, ); assert!( custom_tag_scalar_id > 0, "Failed to add scalar node with custom tag" ); // Test adding scalars with different styles let styles = [ YamlScalarStyleT::YamlPlainScalarStyle, YamlScalarStyleT::YamlSingleQuotedScalarStyle, YamlScalarStyleT::YamlDoubleQuotedScalarStyle, YamlScalarStyleT::YamlLiteralScalarStyle, YamlScalarStyleT::YamlFoldedScalarStyle, ]; for style in &styles { let style_scalar_id = yaml_document_add_scalar( &mut doc, ptr::null(), b"Styled scalar\0".as_ptr(), 14, *style, ); assert!( style_scalar_id > 0, "Failed to add scalar node with style {:?}", style ); } // Verify that we can retrieve the added scalars let empty_scalar = yaml_document_get_node(&mut doc, empty_scalar_id); assert!( !empty_scalar.is_null(), "Failed to retrieve empty scalar node" ); assert_eq!( (*empty_scalar).type_, YamlScalarNode, "Node is not a scalar" ); assert_eq!( (*empty_scalar).data.scalar.length, 0, "Empty scalar should have length 0" ); let non_empty_scalar = yaml_document_get_node(&mut doc, non_empty_scalar_id); assert!( !non_empty_scalar.is_null(), "Failed to retrieve non-empty scalar node" ); assert_eq!( (*non_empty_scalar).type_, YamlScalarNode, "Node is not a scalar" ); assert_eq!( (*non_empty_scalar).data.scalar.length, 13, "Non-empty scalar should have length 13" ); let custom_tag_scalar = yaml_document_get_node(&mut doc, custom_tag_scalar_id); assert!( !custom_tag_scalar.is_null(), "Failed to retrieve custom tag scalar node" ); assert_eq!( (*custom_tag_scalar).type_, YamlScalarNode, "Node is not a scalar" ); assert_eq!( std::ffi::CStr::from_ptr( (*custom_tag_scalar).tag as *const i8 ) .to_bytes(), b"!custom", "Custom tag not set correctly" ); doc.cleanup(); } } } libyml-0.0.5/tests/test_dumper.rs000064400000000000000000000205711046102023000151660ustar 00000000000000#[cfg(test)] mod tests { use libyml::externs::{free, malloc}; use libyml::success::{FAIL, OK}; use libyml::yaml::YamlEmitterT; use libyml::yaml_emitter_close; use libyml::{ libc, yaml_emitter_delete, yaml_emitter_initialize, yaml_emitter_open, }; use std::ptr; /// Dummy write handler function that simulates writing without actually performing any I/O. /// Always returns 1 to indicate success. unsafe fn dummy_write_handler( _data: *mut libc::c_void, _buffer: *mut libc::c_uchar, _size: u64, ) -> libc::c_int { 1 } /// Initializes a YamlEmitterT instance with a dummy write handler. /// Allocates memory, initializes the emitter, and assigns a write handler. unsafe fn initialize_emitter() -> *mut YamlEmitterT { let emitter = malloc(size_of::().try_into().unwrap()) as *mut YamlEmitterT; let _ = yaml_emitter_initialize(emitter); (*emitter).write_handler = Some(dummy_write_handler); emitter } /// Cleans up the YamlEmitterT instance by deleting the emitter and freeing allocated memory. unsafe fn cleanup_emitter(emitter: *mut YamlEmitterT) { yaml_emitter_delete(emitter); free(emitter as *mut libc::c_void); } /// Tests that opening a null emitter pointer fails. #[test] fn test_yaml_emitter_open_failure() { let emitter_ptr: *mut YamlEmitterT = ptr::null_mut(); let result = unsafe { yaml_emitter_open(emitter_ptr) }; assert_eq!(result, FAIL); } /// Tests that a newly initialized emitter can be successfully opened. #[test] fn test_yaml_emitter_open_success() { unsafe { let emitter_ptr = initialize_emitter(); let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); assert!( (*emitter_ptr).opened, "Emitter not opened after successful call" ); cleanup_emitter(emitter_ptr); } } /// Tests that attempting to open an already opened emitter fails. #[test] fn test_yaml_emitter_open_already_opened() { unsafe { let emitter_ptr = initialize_emitter(); let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); let result = yaml_emitter_open(emitter_ptr); assert_eq!( result, FAIL, "Expected FAIL when opening an already opened emitter" ); cleanup_emitter(emitter_ptr); } } /// Tests that an opened emitter can be successfully closed. #[test] fn test_yaml_emitter_open_close() { unsafe { let emitter_ptr = initialize_emitter(); let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); let result = yaml_emitter_close(emitter_ptr); assert_eq!(result, OK); assert!( (*emitter_ptr).closed, "Emitter not closed after successful call" ); cleanup_emitter(emitter_ptr); } } /// Tests that closing an already closed emitter is handled gracefully. #[test] fn test_yaml_emitter_close_already_closed() { unsafe { let emitter_ptr = initialize_emitter(); let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); let result = yaml_emitter_close(emitter_ptr); assert_eq!(result, OK); let result = yaml_emitter_close(emitter_ptr); assert_eq!( result, OK, "Expected OK when closing an already closed emitter" ); cleanup_emitter(emitter_ptr); } } /// Tests that a newly initialized emitter has the correct initial state. #[test] fn test_yaml_emitter_initialize() { unsafe { let emitter_ptr = malloc(size_of::().try_into().unwrap()) as *mut YamlEmitterT; let result = yaml_emitter_initialize(emitter_ptr); assert_eq!(result, OK); assert!(!(*emitter_ptr).opened); assert!(!(*emitter_ptr).closed); yaml_emitter_delete(emitter_ptr); free(emitter_ptr as *mut libc::c_void); } } /// Tests that deleting an emitter works and does not cause crashes. #[test] fn test_yaml_emitter_delete() { unsafe { let emitter_ptr = initialize_emitter(); yaml_emitter_delete(emitter_ptr); free(emitter_ptr as *mut libc::c_void); } } /// Tests that closing an emitter that was never opened is handled correctly. #[test] fn test_yaml_emitter_close_without_open() { unsafe { let emitter_ptr = initialize_emitter(); let result = yaml_emitter_close(emitter_ptr); assert_eq!( result, OK, "Expected OK when closing an unopened emitter" ); assert!( !(*emitter_ptr).opened, "Emitter should not be marked as opened" ); assert!( !(*emitter_ptr).closed, "Emitter should not be marked as closed" ); cleanup_emitter(emitter_ptr); } } /// Tests the ability to emit YAML content using the emitter. #[test] fn test_yaml_emitter_dump() { unsafe { // Step 1: Initialize the emitter let emitter_ptr = initialize_emitter(); // Step 2: Open the emitter let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); // Step 3: Emit some YAML content let yaml_content = "---\nkey: value\n"; // Example YAML content let yaml_bytes = yaml_content.as_bytes(); for &byte in yaml_bytes { let mut mutable_byte = byte; let byte_ptr: *mut u8 = &mut mutable_byte; // Create a raw pointer from the byte variable let result = ((*emitter_ptr).write_handler.unwrap())( emitter_ptr as *mut _ as *mut libc::c_void, // Passing the emitter's context byte_ptr, 1, ); assert_eq!(result, 1); } // Step 4: Close the emitter let result = yaml_emitter_close(emitter_ptr); assert_eq!(result, OK); // Step 5: Cleanup cleanup_emitter(emitter_ptr); } } /// Tests the behavior when the write handler is not set (None). /// Ensures that the system handles the absence of a write handler gracefully. #[test] fn test_yaml_emitter_no_write_handler() { unsafe { let emitter_ptr = initialize_emitter(); // Set the write handler to None (*emitter_ptr).write_handler = None; let result = yaml_emitter_open(emitter_ptr); assert_eq!(result, OK); let yaml_content = "---\nkey: value\n"; let yaml_bytes = yaml_content.as_bytes(); for &byte in yaml_bytes { // Check that the write handler is None if let Some(write_handler) = (*emitter_ptr).write_handler { // If there's a write handler, use it let mut mutable_byte = byte; let byte_ptr: *mut u8 = &mut mutable_byte; let result = write_handler( emitter_ptr as *mut _ as *mut libc::c_void, byte_ptr, 1, ); assert_eq!( result, 1, "Write handler should succeed" ); } else { // Handle the None case assert!( (*emitter_ptr).write_handler.is_none(), "Write handler should be None" ); let expected_failure = true; assert!( expected_failure, "Expected failure when write handler is None" ); } } cleanup_emitter(emitter_ptr); } } } libyml-0.0.5/tests/test_emitter.rs000064400000000000000000000023111046102023000153330ustar 00000000000000#![allow(clippy::type_complexity, clippy::uninlined_format_args)] mod bin; #[path = "../src/bin/run-emitter-test-suite.rs"] #[allow(dead_code)] mod run_emitter_test_suite; use std::fs; use std::io::{Read, Write}; use std::path::Path; // Add this wrapper function unsafe fn unsafe_main_wrapper( stdin: &mut dyn Read, stdout: &mut dyn Write, ) -> Result<(), bin::MyError> { run_emitter_test_suite::unsafe_main(stdin, stdout) .map_err(|e| bin::MyError::Other(e.to_string())) } fn test(id: &str) { let dir = Path::new("tests") .join("data") .join("yaml-test-suite") .join(id); let output = bin::run( env!("CARGO_BIN_EXE_run-emitter-test-suite"), unsafe_main_wrapper, &dir.join("test.event"), ); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); eprint!("{}", stderr); let out = if dir.join("out.yaml").exists() { dir.join("out.yaml") } else { dir.join("in.yaml") }; let expected = fs::read_to_string(out).unwrap(); pretty_assertions::assert_str_eq!(expected, stdout); assert!(output.success); } libyml_test_suite::test_emitter!(); libyml-0.0.5/tests/test_internal.rs000064400000000000000000000056171046102023000155120ustar 00000000000000use libyml::{ internal::{yaml_check_utf8, yaml_queue_extend, yaml_stack_extend}, memory::{yaml_free, yaml_malloc}, success::{FAIL, OK}, }; #[cfg(test)] mod tests { use super::*; /// Tests for yaml_stack_extend function #[test] fn test_yaml_stack_extend() { unsafe { // Initialize a small stack let mut start = yaml_malloc(16); let mut top = start; let mut end = start.add(16); // Extend the stack yaml_stack_extend(&mut start, &mut top, &mut end); // Check if the stack size doubled assert_eq!(end.offset_from(start), 32); // Clean up yaml_free(start); } } /// Tests for yaml_queue_extend function #[test] fn test_yaml_queue_extend() { unsafe { // Initialize a small queue let mut start = yaml_malloc(16); let mut head = start; let mut tail = start; let mut end = start.add(32); // Extend the queue yaml_queue_extend( &mut start, &mut head, &mut tail, &mut end, ); // Check if the queue size doubled assert_eq!(end.offset_from(start), 32); // Clean up yaml_free(start); } } /// Tests for yaml_check_utf8 function #[test] fn test_yaml_check_utf8() { unsafe { // Valid UTF-8 string let valid_str = "Hello, world!"; assert_eq!( yaml_check_utf8( valid_str.as_ptr(), valid_str.len().try_into().unwrap() ), OK ); // Invalid UTF-8 string let invalid_str = [0xFF, 0xFE, 0xFD]; assert_eq!( yaml_check_utf8( invalid_str.as_ptr(), invalid_str.len().try_into().unwrap() ), FAIL ); // Empty string let empty_str = ""; assert_eq!( yaml_check_utf8( empty_str.as_ptr(), empty_str.len().try_into().unwrap() ), OK ); // Multi-byte UTF-8 characters let multi_byte_str = "こんにちは"; assert_eq!( yaml_check_utf8( multi_byte_str.as_ptr(), multi_byte_str.len().try_into().unwrap() ), OK ); // Incomplete multi-byte sequence let incomplete_str = [0xE3, 0x81, 0x93, 0xE3, 0x81]; assert_eq!( yaml_check_utf8( incomplete_str.as_ptr(), incomplete_str.len().try_into().unwrap() ), FAIL ); } } } libyml-0.0.5/tests/test_lib.rs000064400000000000000000000073461046102023000144450ustar 00000000000000#![no_std] #[cfg(test)] mod tests { use core::mem::MaybeUninit; use libyml::success::is_success; use libyml::*; /// Tests the initialization and deletion of the YAML parser. #[test] fn test_parser_initialize_and_delete() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let mut parser = parser.assume_init(); yaml_parser_delete(&mut parser); } } /// Tests setting the input string for the YAML parser. #[test] fn test_parser_set_input_string() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let mut parser = parser.assume_init(); let input = b"key: value\n"; yaml_parser_set_input_string( &mut parser, input.as_ptr(), input.len() as u64, ); yaml_parser_delete(&mut parser); } } /// Tests parsing a simple YAML document. #[test] fn test_parser_parse_simple_document() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let mut parser = parser.assume_init(); let input = b"key: value\n"; yaml_parser_set_input_string( &mut parser, input.as_ptr(), input.len() as u64, ); let mut event = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_parse( &mut parser, event.as_mut_ptr() ))); let _event = event.assume_init(); yaml_parser_delete(&mut parser); } } /// Tests parsing of a complex YAML document with nested structures. #[test] fn test_complex_document() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let mut parser = parser.assume_init(); let input = b" parent: child1: value1 child2: - list_item1 - list_item2 "; yaml_parser_set_input_string( &mut parser, input.as_ptr(), input.len() as u64, ); let mut event = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_parse( &mut parser, event.as_mut_ptr() ))); let _event = event.assume_init(); yaml_parser_delete(&mut parser); } } /// Tests handling invalid YAML input. #[test] fn test_parser_handle_invalid_input() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let mut parser = parser.assume_init(); let input = b"invalid_yaml"; yaml_parser_set_input_string( &mut parser, input.as_ptr(), input.len() as u64, ); let mut event = MaybeUninit::::uninit(); let result = yaml_parser_parse(&mut parser, event.as_mut_ptr()); assert!(is_success(result)); yaml_parser_delete(&mut parser); } } } libyml-0.0.5/tests/test_loader.rs000064400000000000000000000047661046102023000151500ustar 00000000000000#[cfg(test)] mod tests { use core::ffi::c_char; use core::mem::MaybeUninit; use libyml::api::yaml_parser_set_input_string; use libyml::decode::yaml_parser_initialize; use libyml::loader::yaml_parser_set_composer_error; use libyml::success::is_success; use libyml::yaml::YamlErrorTypeT::YamlComposerError; use libyml::{ yaml_document_delete, yaml_parser_delete, yaml_parser_load, YamlDocumentT, YamlMarkT, YamlParserT, }; #[test] fn test_yaml_parser_load() { unsafe { let mut parser = MaybeUninit::::uninit(); let mut document = MaybeUninit::::uninit(); let input = b"key: value\n"; // Initialize the parser assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let parser = parser.assume_init_mut(); // Set the input string yaml_parser_set_input_string( parser, input.as_ptr(), input.len() as u64, ); // Load the document let result = yaml_parser_load(parser, document.as_mut_ptr()); assert!(is_success(result)); // Clean up yaml_document_delete(document.as_mut_ptr()); yaml_parser_delete(parser); } } // Test for yaml_parser_set_composer_error #[test] fn test_yaml_parser_set_composer_error() { unsafe { let mut parser = MaybeUninit::::uninit(); assert!(is_success(yaml_parser_initialize( parser.as_mut_ptr() ))); let parser = parser.assume_init_mut(); let problem = b"Test problem\0" as *const u8 as *const c_char; let problem_mark = YamlMarkT::default(); // Call the function that sets the error let _ = yaml_parser_set_composer_error( parser, problem, problem_mark, ); // Check if the error is set correctly assert_eq!(parser.error, YamlComposerError); assert_eq!(parser.problem, problem); assert_eq!(parser.problem_mark.index, problem_mark.index); assert_eq!(parser.problem_mark.line, problem_mark.line); assert_eq!(parser.problem_mark.column, problem_mark.column); // Clean up yaml_parser_delete(parser); } } } libyml-0.0.5/tests/test_macros.rs000064400000000000000000000232421046102023000151540ustar 00000000000000#[cfg(test)] mod tests { use core::ptr; use core::ptr::addr_of_mut; use core::ptr::null_mut; use libyml::externs::{free, malloc, memset}; use libyml::libc; use libyml::string::yaml_string_extend; use libyml::string::yaml_string_join; use libyml::yaml::{size_t, yaml_char_t}; use libyml::{ AS_DIGIT, AS_HEX_AT, BUFFER_DEL, BUFFER_INIT, CLEAR, IS_ALPHA, IS_ASCII, IS_DIGIT, IS_HEX_AT, JOIN, STRING_ASSIGN, STRING_DEL, STRING_EXTEND, STRING_INIT, }; #[derive(Debug, PartialEq)] struct YamlBufferT { start: *mut yaml_char_t, pointer: *mut yaml_char_t, last: *mut yaml_char_t, end: *mut yaml_char_t, } #[derive(Debug, PartialEq)] struct YamlStringT { start: *mut yaml_char_t, pointer: *mut yaml_char_t, end: *mut yaml_char_t, } // Mock implementation of the `yaml_malloc` function #[no_mangle] extern "C" fn yaml_malloc(size: size_t) -> *mut libc::c_void { unsafe { malloc(size) } } // Mock implementation of the `yaml_free` function #[no_mangle] extern "C" fn yaml_free(ptr: *mut libc::c_void) { unsafe { free(ptr) } } // // Mock implementation of the `yaml_string_join` function // #[no_mangle] // extern "C" { // fn memset(s: *mut libc::c_void, c: libc::c_int, n: size_t) -> *mut libc::c_void; // fn yaml_string_join( // a_start: *mut *mut yaml_char_t, // a_pointer: *mut *mut yaml_char_t, // a_end: *mut *mut yaml_char_t, // b_start: *mut *mut yaml_char_t, // b_pointer: *mut *mut yaml_char_t, // b_end: *mut *mut yaml_char_t, // ); // } #[test] fn test_buffer_init() { let mut buffer = YamlBufferT { start: null_mut(), pointer: null_mut(), last: null_mut(), end: null_mut(), }; let size = 16; unsafe { BUFFER_INIT!(buffer, size); } assert!(!buffer.start.is_null()); assert_eq!(buffer.pointer, buffer.start); assert_eq!(buffer.last, buffer.start); assert_eq!(buffer.end, unsafe { buffer.start.add(size) }); } #[test] fn test_buffer_del() { let mut buffer = YamlBufferT { start: yaml_malloc(16) as *mut yaml_char_t, pointer: null_mut(), last: null_mut(), end: null_mut(), }; buffer.pointer = buffer.start; buffer.last = buffer.start; buffer.end = unsafe { buffer.start.add(16) }; BUFFER_DEL!(buffer); assert!(buffer.start.is_null()); assert_eq!(buffer.pointer, buffer.start); assert_eq!(buffer.last, buffer.start); assert_eq!(buffer.end, buffer.start); } #[test] fn test_string_assign() { let start_ptr = 0x1000 as *mut yaml_char_t; let length: isize = 10; let yaml_str = STRING_ASSIGN!(start_ptr, length); assert_eq!(yaml_str.start, start_ptr); assert_eq!(yaml_str.end, unsafe { start_ptr.add(length as usize) }); assert_eq!(yaml_str.pointer, start_ptr); } #[test] fn test_string_init() { let mut yaml_str = YamlStringT { start: null_mut(), pointer: null_mut(), end: null_mut(), }; unsafe { STRING_INIT!(yaml_str); } assert!(!yaml_str.start.is_null()); assert_eq!(yaml_str.pointer, yaml_str.start); assert_eq!(yaml_str.end, unsafe { yaml_str.start.add(16) }); // Optionally, add a check for the memory content if necessary } #[test] fn test_string_del() { let mut yaml_str = YamlStringT { start: yaml_malloc(16) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(16) }; STRING_DEL!(yaml_str); assert!(yaml_str.start.is_null()); assert_eq!(yaml_str.pointer, yaml_str.start); assert_eq!(yaml_str.end, yaml_str.start); } #[test] fn test_string_extend() { let mut yaml_str = YamlStringT { start: yaml_malloc(5) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(5) }; unsafe { STRING_EXTEND!(yaml_str); } unsafe { assert!(yaml_str.end > yaml_str.start.add(5)); } } #[test] fn test_clear() { let mut yaml_str = YamlStringT { start: yaml_malloc(16) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = unsafe { yaml_str.start.add(8) }; // Simulate some data yaml_str.end = unsafe { yaml_str.start.add(16) }; unsafe { CLEAR!(yaml_str); } assert_eq!(yaml_str.pointer, yaml_str.start); // Check if memory is zeroed for i in 0..16 { assert_eq!(unsafe { *yaml_str.start.add(i) }, 0); } } #[test] fn test_join() { let mut string_a = YamlStringT { start: yaml_malloc(16) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; string_a.pointer = string_a.start; string_a.end = unsafe { string_a.start.add(16) }; let mut string_b = YamlStringT { start: yaml_malloc(8) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; string_b.pointer = string_b.start; string_b.end = unsafe { string_b.start.add(8) }; // Fill string_b with some data unsafe { ptr::copy_nonoverlapping( "Hello".as_ptr(), string_b.start, 5, ); string_b.pointer = string_b.pointer.add(5); } unsafe { JOIN!(string_a, string_b); } assert_eq!( unsafe { string_a.pointer.offset_from(string_a.start) }, 5 ); assert_eq!(unsafe { *string_a.start as char }, 'H'); assert_eq!(unsafe { *string_a.start.add(4) as char }, 'o'); } // Tests for character classification macros #[test] fn test_is_alpha() { let mut yaml_str = YamlStringT { start: yaml_malloc(3) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(3) }; unsafe { *yaml_str.pointer = b'A'; assert!(IS_ALPHA!(yaml_str)); *yaml_str.pointer = b'z'; assert!(IS_ALPHA!(yaml_str)); *yaml_str.pointer = b'5'; assert!(IS_ALPHA!(yaml_str)); *yaml_str.pointer = b'_'; assert!(IS_ALPHA!(yaml_str)); *yaml_str.pointer = b'-'; assert!(IS_ALPHA!(yaml_str)); *yaml_str.pointer = b'!'; assert!(!IS_ALPHA!(yaml_str)); } } #[test] fn test_is_digit() { let mut yaml_str = YamlStringT { start: yaml_malloc(2) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(2) }; unsafe { *yaml_str.pointer = b'5'; assert!(IS_DIGIT!(yaml_str)); *yaml_str.pointer = b'A'; assert!(!IS_DIGIT!(yaml_str)); } } #[test] fn test_as_digit() { let mut yaml_str = YamlStringT { start: yaml_malloc(1) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(1) }; unsafe { *yaml_str.pointer = b'5'; assert_eq!(AS_DIGIT!(yaml_str), 5); } } #[test] fn test_is_hex_at() { let mut yaml_str = YamlStringT { start: yaml_malloc(3) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(3) }; unsafe { ptr::copy_nonoverlapping("A5f".as_ptr(), yaml_str.start, 3); assert!(IS_HEX_AT!(yaml_str, 0)); assert!(IS_HEX_AT!(yaml_str, 1)); assert!(IS_HEX_AT!(yaml_str, 2)); } } #[test] fn test_as_hex_at() { let mut yaml_str = YamlStringT { start: yaml_malloc(3) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(3) }; unsafe { ptr::copy_nonoverlapping("A5f".as_ptr(), yaml_str.start, 3); assert_eq!(AS_HEX_AT!(yaml_str, 0), 10); assert_eq!(AS_HEX_AT!(yaml_str, 1), 5); assert_eq!(AS_HEX_AT!(yaml_str, 2), 15); } } #[test] fn test_is_ascii() { let mut yaml_str = YamlStringT { start: yaml_malloc(2) as *mut yaml_char_t, pointer: null_mut(), end: null_mut(), }; yaml_str.pointer = yaml_str.start; yaml_str.end = unsafe { yaml_str.start.add(2) }; unsafe { *yaml_str.pointer = 0x7F; assert!(IS_ASCII!(yaml_str)); *yaml_str.pointer = 0x80; assert!(!IS_ASCII!(yaml_str)); } } } libyml-0.0.5/tests/test_memory.rs000064400000000000000000000054501046102023000152010ustar 00000000000000#[cfg(test)] mod tests { use core::ffi::c_void; use core::ptr; use libyml::memory::*; /// Tests that `yaml_malloc` successfully allocates memory. #[test] fn test_yaml_malloc() { unsafe { let ptr = yaml_malloc(10); assert!(!ptr.is_null()); yaml_free(ptr); } } /// Tests that `yaml_realloc` successfully reallocates memory. #[test] fn test_yaml_realloc() { unsafe { let ptr = yaml_malloc(10); assert!(!ptr.is_null()); let new_ptr = yaml_realloc(ptr, 20); assert!(!new_ptr.is_null()); yaml_free(new_ptr); } } /// Tests that `yaml_realloc` behaves correctly when given a null pointer. #[test] fn test_yaml_realloc_null() { unsafe { let ptr = yaml_realloc(ptr::null_mut(), 10); assert!(!ptr.is_null()); yaml_free(ptr); } } /// Tests that `yaml_free` successfully frees allocated memory. #[test] fn test_yaml_free() { unsafe { let ptr = yaml_malloc(10); assert!(!ptr.is_null()); yaml_free(ptr); // We can't really test much after freeing, as using the pointer would be undefined behavior } } /// Tests that `yaml_free` behaves correctly when given a null pointer. #[test] fn test_yaml_free_null() { unsafe { // This should not cause any errors yaml_free(ptr::null_mut()); } } /// Tests that `yaml_strdup` correctly duplicates a string. #[test] fn test_yaml_strdup() { unsafe { let original = b"test string\0" as *const u8; let duped_ptr = yaml_strdup(original); assert!(!duped_ptr.is_null()); // Compare the strings let mut i = 0; while *original.add(i) != 0 { assert_eq!(*original.add(i), *duped_ptr.add(i)); i += 1; } assert_eq!(*duped_ptr.add(i), 0); // Null terminator yaml_free(duped_ptr as *mut c_void); } } /// Tests that `yaml_strdup` returns a null pointer when given a null pointer. #[test] fn test_yaml_strdup_null() { unsafe { let duped_ptr = yaml_strdup(ptr::null()); assert!(duped_ptr.is_null()); } } /// Tests that `yaml_strdup` correctly duplicates an empty string. #[test] fn test_yaml_strdup_empty_string() { unsafe { let original = b"\0" as *const u8; let duped_ptr = yaml_strdup(original); assert!(!duped_ptr.is_null()); assert_eq!(*duped_ptr, 0); // Should only contain null terminator yaml_free(duped_ptr as *mut c_void); } } } libyml-0.0.5/tests/test_parser.rs000064400000000000000000000334331046102023000151670ustar 00000000000000//! This module contains tests for the YAML parser functionality. //! It includes both general parsing tests and specific test cases for various YAML features. #![allow(clippy::type_complexity, clippy::uninlined_format_args)] use std::fs; use std::io::{Read, Write}; use std::path::Path; mod bin; #[path = "../src/bin/run-parser-test-suite.rs"] #[allow(dead_code)] mod run_parser_test_suite; /// Wrapper function to bridge the error types between the test suite and the parser. /// /// # Safety /// /// This function is unsafe because it calls an unsafe function `unsafe_main`. /// The caller must ensure that the provided `stdin` and `stdout` are valid for the lifetime of the call. /// /// # Arguments /// /// * `stdin` - A mutable reference to a type that implements `Read` /// * `stdout` - A mutable reference to a type that implements `Write` /// /// # Returns /// /// Returns `Ok(())` if parsing succeeds, or `Err(bin::MyError)` if an error occurs. unsafe fn unsafe_main_wrapper( stdin: &mut dyn Read, stdout: &mut dyn Write, ) -> Result<(), bin::MyError> { run_parser_test_suite::unsafe_main(stdin, stdout) .map_err(|e| bin::MyError::Other(e.to_string())) } /// Test function for running parser tests from the YAML Test Suite /// /// # Arguments /// /// * `id` - A string slice that holds the identifier for the test case /// /// # Panics /// /// This function will panic if the parser output doesn't match the expected output or if the parser fails unexpectedly. fn test(id: &str) { let dir = Path::new("tests") .join("data") .join("yaml-test-suite") .join(id); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &dir.join("in.yaml"), ); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); eprint!("{}", stderr); let expected = fs::read_to_string(dir.join("test.event")).unwrap(); pretty_assertions::assert_str_eq!(expected, stdout); assert!(output.success); } /// Test parsing of an empty YAML file #[test] fn test_empty_file() { let temp_file = Path::new("tests").join("empty.yaml"); fs::write(&temp_file, "").unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); assert!(output.success, "Parser should succeed for empty file"); let stdout = String::from_utf8_lossy(&output.stdout); assert!( stdout.contains("+STR") && stdout.contains("-STR"), "Empty file should still have stream start/end" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of a simple scalar YAML #[test] fn test_scalar_parsing() { let yaml = "scalar: value"; let temp_file = Path::new("tests").join("temp_scalar.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); println!("Actual output:\n{}", stdout); assert!(output.success, "Parser did not exit successfully"); assert!(stdout.contains("+STR"), "Output doesn't contain '+STR'"); assert!(stdout.contains("+DOC"), "Output doesn't contain '+DOC'"); assert!(stdout.contains("+MAP"), "Output doesn't contain '+MAP'"); assert!( stdout.contains("=VAL :scalar"), "Output doesn't contain '=VAL :scalar'" ); assert!( stdout.contains("=VAL :value"), "Output doesn't contain '=VAL :value'" ); assert!(stdout.contains("-MAP"), "Output doesn't contain '-MAP'"); assert!(stdout.contains("-DOC"), "Output doesn't contain '-DOC'"); assert!(stdout.contains("-STR"), "Output doesn't contain '-STR'"); fs::remove_file(temp_file).unwrap(); } /// Test parsing of a YAML sequence #[test] fn test_sequence_parsing() { let yaml = "- item1\n- item2\n- item3"; let temp_file = Path::new("tests").join("temp_sequence.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); println!("Actual output:\n{}", stdout); assert!(output.success, "Parser did not exit successfully"); assert!(stdout.contains("+STR"), "Output doesn't contain '+STR'"); assert!(stdout.contains("+DOC"), "Output doesn't contain '+DOC'"); assert!(stdout.contains("+SEQ"), "Output doesn't contain '+SEQ'"); assert!( stdout.contains("=VAL :item1"), "Output doesn't contain '=VAL :item1'" ); assert!( stdout.contains("=VAL :item2"), "Output doesn't contain '=VAL :item2'" ); assert!( stdout.contains("=VAL :item3"), "Output doesn't contain '=VAL :item3'" ); assert!(stdout.contains("-SEQ"), "Output doesn't contain '-SEQ'"); assert!(stdout.contains("-DOC"), "Output doesn't contain '-DOC'"); assert!(stdout.contains("-STR"), "Output doesn't contain '-STR'"); fs::remove_file(temp_file).unwrap(); } /// Test parsing of a YAML mapping #[test] fn test_mapping_parsing() { let yaml = "key1: value1\nkey2: value2"; let temp_file = Path::new("tests").join("temp_mapping.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); println!("Actual output:\n{}", stdout); assert!(output.success, "Parser did not exit successfully"); assert!(stdout.contains("+STR"), "Output doesn't contain '+STR'"); assert!(stdout.contains("+DOC"), "Output doesn't contain '+DOC'"); assert!(stdout.contains("+MAP"), "Output doesn't contain '+MAP'"); assert!( stdout.contains("=VAL :key1"), "Output doesn't contain '=VAL :key1'" ); assert!( stdout.contains("=VAL :value1"), "Output doesn't contain '=VAL :value1'" ); assert!( stdout.contains("=VAL :key2"), "Output doesn't contain '=VAL :key2'" ); assert!( stdout.contains("=VAL :value2"), "Output doesn't contain '=VAL :value2'" ); assert!(stdout.contains("-MAP"), "Output doesn't contain '-MAP'"); assert!(stdout.contains("-DOC"), "Output doesn't contain '-DOC'"); assert!(stdout.contains("-STR"), "Output doesn't contain '-STR'"); fs::remove_file(temp_file).unwrap(); } /// Test parsing of nested YAML structures #[test] fn test_nested_structures() { let yaml = " outer: inner: - item1 - item2: subkey: subvalue "; let temp_file = Path::new("tests").join("nested.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); assert!(output.success, "Parser did not exit successfully"); assert!(stdout.contains("+MAP"), "Output doesn't contain '+MAP'"); assert!(stdout.contains("+SEQ"), "Output doesn't contain '+SEQ'"); assert!( stdout.contains("=VAL :outer"), "Output doesn't contain '=VAL :outer'" ); assert!( stdout.contains("=VAL :inner"), "Output doesn't contain '=VAL :inner'" ); assert!( stdout.contains("=VAL :item1"), "Output doesn't contain '=VAL :item1'" ); assert!( stdout.contains("=VAL :item2"), "Output doesn't contain '=VAL :item2'" ); assert!( stdout.contains("=VAL :subkey"), "Output doesn't contain '=VAL :subkey'" ); assert!( stdout.contains("=VAL :subvalue"), "Output doesn't contain '=VAL :subvalue'" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML with anchors and aliases #[test] fn test_anchors_and_aliases() { let yaml = " anchor: &anchor_value key: value alias: *anchor_value "; let temp_file = Path::new("tests").join("anchors.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); assert!(output.success, "Parser did not exit successfully"); assert!( stdout.contains("&anchor_value"), "Output doesn't contain '&anchor_value'" ); assert!( stdout.contains("*anchor_value"), "Output doesn't contain '*anchor_value'" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML with multiline strings #[test] fn test_multiline_strings() { let yaml = r#" literal: | This is a multiline string folded: > This is another multiline string "#; let temp_file = Path::new("tests").join("multiline.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); assert!(output.success, "Parser did not exit successfully"); assert!( stdout.contains("=VAL |"), "Output doesn't contain literal multiline indicator" ); assert!( stdout.contains("=VAL >"), "Output doesn't contain folded multiline indicator" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML in flow style #[test] fn test_flow_style() { let yaml = "{key1: value1, key2: [item1, item2]}"; let temp_file = Path::new("tests").join("flow_style.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); assert!(output.success, "Parser did not exit successfully"); assert!(stdout.contains("+MAP"), "Output doesn't contain '+MAP'"); assert!(stdout.contains("+SEQ"), "Output doesn't contain '+SEQ'"); assert!( stdout.contains("=VAL :key1"), "Output doesn't contain '=VAL :key1'" ); assert!( stdout.contains("=VAL :value1"), "Output doesn't contain '=VAL :value1'" ); assert!( stdout.contains("=VAL :key2"), "Output doesn't contain '=VAL :key2'" ); assert!( stdout.contains("=VAL :item1"), "Output doesn't contain '=VAL :item1'" ); assert!( stdout.contains("=VAL :item2"), "Output doesn't contain '=VAL :item2'" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML with Unicode characters #[test] fn test_unicode() { let yaml = "unicode: 你好世界"; let temp_file = Path::new("tests").join("unicode.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); assert!( output.success, "Parser should succeed for Unicode content" ); let stdout = String::from_utf8_lossy(&output.stdout); assert!( stdout.contains("你好世界"), "Unicode characters should be preserved" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML with comments #[test] fn test_comments() { let yaml = "key: value # This is a comment\n# This is another comment\nother: value"; let temp_file = Path::new("tests").join("comments.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); assert!( output.success, "Parser should succeed for YAML with comments" ); let stdout = String::from_utf8_lossy(&output.stdout); assert!( !stdout.contains("# This is a comment"), "Comments should be ignored in the output" ); fs::remove_file(temp_file).unwrap(); } /// Test parsing of YAML with directives #[test] fn test_yaml_directive() { let yaml = "%YAML 1.2\n---\nkey: value"; let temp_file = Path::new("tests").join("directive.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); let stdout = String::from_utf8_lossy(&output.stdout); println!("Actual output:\n{}", stdout); assert!( output.success, "Parser should succeed for YAML with directives" ); assert!(stdout.contains("+STR"), "Output doesn't contain '+STR'"); assert!(stdout.contains("+DOC"), "Output doesn't contain '+DOC'"); assert!(stdout.contains("+MAP"), "Output doesn't contain '+MAP'"); assert!( stdout.contains("=VAL :key"), "Output doesn't contain '=VAL :key'" ); assert!( stdout.contains("=VAL :value"), "Output doesn't contain '=VAL :value'" ); assert!(stdout.contains("-MAP"), "Output doesn't contain '-MAP'"); assert!(stdout.contains("-DOC"), "Output doesn't contain '-DOC'"); assert!(stdout.contains("-STR"), "Output doesn't contain '-STR'"); fs::remove_file(temp_file).unwrap(); } /// Test parsing of invalid YAML #[test] fn test_invalid_yaml() { let yaml = "key: : value"; let temp_file = Path::new("tests").join("invalid.yaml"); fs::write(&temp_file, yaml).unwrap(); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &temp_file, ); assert!(!output.success, "Parser should fail for invalid YAML"); fs::remove_file(temp_file).unwrap(); } // Run the test suite for parser libyml_test_suite::test_parser!(); libyml-0.0.5/tests/test_parser_error.rs000064400000000000000000000044751046102023000164040ustar 00000000000000//! This module contains tests for the YAML parser error handling. //! It ensures that the parser correctly identifies and reports errors in invalid YAML documents. #![allow(clippy::type_complexity, clippy::uninlined_format_args)] use std::io::{Read, Write}; use std::path::Path; mod bin; #[path = "../src/bin/run-parser-test-suite.rs"] #[allow(dead_code)] mod run_parser_test_suite; /// Wrapper function to bridge the error types between the test suite and the parser. /// /// This function wraps the `unsafe_main` function from the parser test suite, /// converting its `anyhow::Error` into the `bin::MyError` expected by the test runner. /// /// # Safety /// /// This function is unsafe because it calls an unsafe function `unsafe_main`. /// The caller must ensure that the provided `stdin` and `stdout` are valid for the lifetime of the call. /// /// # Arguments /// /// * `stdin` - A mutable reference to a type that implements `Read` /// * `stdout` - A mutable reference to a type that implements `Write` /// /// # Returns /// /// Returns `Ok(())` if parsing succeeds, or `Err(bin::MyError)` if an error occurs. unsafe fn unsafe_main_wrapper( stdin: &mut dyn Read, stdout: &mut dyn Write, ) -> Result<(), bin::MyError> { run_parser_test_suite::unsafe_main(stdin, stdout) .map_err(|e| bin::MyError::Other(e.to_string())) } /// Runs a single parser error test case. /// /// This function sets up the test environment, runs the parser on the input file, /// and checks that the parser fails as expected for invalid YAML. /// /// # Arguments /// /// * `id` - A string slice that holds the identifier for the test case /// /// # Panics /// /// This function will panic if the parser succeeds on an input that should fail. fn test(id: &str) { let dir = Path::new("tests") .join("data") .join("yaml-test-suite") .join(id); let output = bin::run( env!("CARGO_BIN_EXE_run-parser-test-suite"), unsafe_main_wrapper, &dir.join("in.yaml"), ); if output.success { let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); eprint!("{}", stdout); eprint!("{}", stderr); panic!("expected parse to fail"); } } // Run the test suite for parser errors libyml_test_suite::test_parser_error!(); libyml-0.0.5/tests/test_string.rs000064400000000000000000000175151046102023000152040ustar 00000000000000#[cfg(test)] mod tests { use core::ffi::c_void; use core::ptr; use libyml::memory::{yaml_free, yaml_malloc}; use libyml::string::*; use libyml::yaml::yaml_char_t; /// Tests that `yaml_string_duplicate` correctly duplicates a non-null string. #[test] fn test_yaml_string_duplicate() { unsafe { let original = b"test string\0" as *const u8; let duped_ptr = yaml_string_duplicate(original); assert!(!duped_ptr.is_null()); // Compare the strings let mut i = 0; while *original.add(i) != 0 { assert_eq!(*original.add(i), *duped_ptr.add(i)); i += 1; } assert_eq!(*duped_ptr.add(i), 0); // Null terminator yaml_free(duped_ptr as *mut c_void); } } /// Tests that `yaml_string_duplicate` returns a null pointer when given a null pointer. #[test] fn test_yaml_string_duplicate_null() { unsafe { let duped_ptr = yaml_string_duplicate(ptr::null()); assert!(duped_ptr.is_null()); } } /// Tests that `yaml_string_duplicate` can correctly duplicate an empty string, /// ensuring the duplicate is not null and contains only the null terminator. #[test] fn test_yaml_string_duplicate_empty_string() { unsafe { let original = b"\0" as *const u8; let duped_ptr = yaml_string_duplicate(original); assert!(!duped_ptr.is_null()); assert_eq!(*duped_ptr, 0); // Should only contain null terminator yaml_free(duped_ptr as *mut c_void); } } /// Tests that `yaml_string_join` correctly joins two non-empty string buffers, /// verifying the content and length of the result. #[test] fn test_yaml_string_join() { unsafe { let mut a_start = yaml_malloc(10) as *mut yaml_char_t; let mut a_pointer = a_start; let mut a_end = a_start.add(10); let mut b_start = b"test" as *const u8 as *mut yaml_char_t; let mut b_pointer = b_start.add(4); let mut b_end = b_start.add(4); yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); assert_eq!(a_pointer.offset_from(a_start), 4); assert_eq!(*a_start, b't'); assert_eq!(*a_start.add(1), b'e'); assert_eq!(*a_start.add(2), b's'); assert_eq!(*a_start.add(3), b't'); yaml_free(a_start as *mut c_void); } } /// Tests that `yaml_string_join` handles joining with an empty buffer correctly, /// ensuring that nothing is copied and pointers remain unchanged. #[test] fn test_yaml_string_join_empty() { unsafe { let mut a_start = yaml_malloc(10) as *mut yaml_char_t; let mut a_pointer = a_start; let mut a_end = a_start.add(10); let mut b_start = b"\0" as *const u8 as *mut yaml_char_t; let mut b_pointer = b_start; let mut b_end = b_start; yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); assert_eq!(a_pointer.offset_from(a_start), 0); // Nothing should be copied yaml_free(a_start as *mut c_void); } } /// Tests that `yaml_string_join` can correctly extend the buffer when the initial buffer /// is too small to contain the joined result, ensuring correct reallocation and copying. #[test] fn test_yaml_string_join_extend() { unsafe { let mut a_start = yaml_malloc(2) as *mut yaml_char_t; let mut a_pointer = a_start; let mut a_end = a_start.add(2); let mut b_start = b"longer string" as *const u8 as *mut yaml_char_t; let mut b_pointer = b_start.add(12); let mut b_end = b_start.add(12); yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); assert!(a_pointer.offset_from(a_start) >= 12); assert_eq!(*a_start, b'l'); assert_eq!(*a_start.add(1), b'o'); assert_eq!(*a_start.add(2), b'n'); assert_eq!(*a_start.add(3), b'g'); yaml_free(a_start as *mut c_void); } } /// Verifies that `yaml_string_duplicate` can accurately duplicate a string that fills /// the entire buffer, ensuring correct memory allocation and duplication integrity. #[test] fn test_yaml_string_duplicate_exact_size() { unsafe { let original = b"exact size\0" as *const u8; let duped_ptr = yaml_string_duplicate(original); assert!(!duped_ptr.is_null()); let mut i = 0; while *original.add(i) != 0 { assert_eq!(*original.add(i), *duped_ptr.add(i)); i += 1; } assert_eq!(*duped_ptr.add(i), 0); // Null terminator yaml_free(duped_ptr as *mut c_void); } } /// Ensures that `yaml_string_join` properly handles cases where the buffer is exactly /// full, confirming that the join operation completes without overflow. #[test] fn test_yaml_string_join_full_buffer() { unsafe { let mut a_start = yaml_malloc(4) as *mut yaml_char_t; let mut a_pointer = a_start; let mut a_end = a_start.add(4); let mut b_start = b"full" as *const u8 as *mut yaml_char_t; let mut b_pointer = b_start.add(4); let mut b_end = b_start.add(4); yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); assert_eq!(a_pointer.offset_from(a_start), 4); assert_eq!(*a_start.add(3), b'l'); yaml_free(a_start as *mut c_void); } } /// Confirms that `yaml_string_join` can handle near-full buffer conditions effectively, /// verifying that the content and pointers are correctly managed without overflow. #[test] fn test_yaml_string_join_near_full_buffer() { unsafe { let mut a_start = yaml_malloc(4) as *mut yaml_char_t; let mut a_pointer = a_start; let mut a_end = a_start.add(4); let b_content = b"full\0"; let mut b_start = b_content.as_ptr() as *mut yaml_char_t; let mut b_pointer = b_start.add(4); // Point to the end of the string let mut b_end = b_start.add(4); yaml_string_join( &mut a_start, &mut a_pointer, &mut a_end, &mut b_start, &mut b_pointer, &mut b_end, ); let offset = a_pointer.offset_from(a_start); assert_eq!( offset, 4, "Expected offset to be 4, but got {}", offset ); assert_eq!( *a_start.add(3), b'l', "Expected last character to be 'l', but got {}", *a_start.add(3) as char ); // Verify the contents of the buffer assert_eq!(*a_start.add(0), b'f'); assert_eq!(*a_start.add(1), b'u'); assert_eq!(*a_start.add(2), b'l'); assert_eq!(*a_start.add(3), b'l'); yaml_free(a_start as *mut c_void); } } } libyml-0.0.5/tests/test_yaml.rs000064400000000000000000000274401046102023000146360ustar 00000000000000#![no_std] #![cfg(test)] use libyml::yaml::*; // Default value tests /// Tests the default values of YamlVersionDirectiveT #[test] fn test_default_yaml_version_directive() { let version_directive = YamlVersionDirectiveT::default(); assert_eq!(version_directive.major, 0); assert_eq!(version_directive.minor, 0); } /// Tests the default values of YamlMarkT #[test] fn test_default_yaml_mark() { let mark = YamlMarkT::default(); assert_eq!(mark.index, 0); assert_eq!(mark.line, 0); assert_eq!(mark.column, 0); } /// Tests the default values of YamlEncodingT #[test] fn test_default_yaml_encoding() { let encoding = YamlEncodingT::default(); assert_eq!(encoding, YamlEncodingT::YamlAnyEncoding); } /// Tests the default values of YamlScalarStyleT #[test] fn test_default_yaml_scalar_style() { let scalar_style = YamlScalarStyleT::default(); assert_eq!(scalar_style, YamlScalarStyleT::YamlAnyScalarStyle); } /// Tests the default values of YamlSequenceStyleT #[test] fn test_default_yaml_sequence_style() { let sequence_style = YamlSequenceStyleT::default(); assert_eq!( sequence_style, YamlSequenceStyleT::YamlAnySequenceStyle ); } /// Tests the default values of YamlMappingStyleT #[test] fn test_default_yaml_mapping_style() { let mapping_style = YamlMappingStyleT::default(); assert_eq!(mapping_style, YamlMappingStyleT::YamlAnyMappingStyle); } /// Tests the default values of YamlTagDirectiveT #[test] fn test_default_yaml_tag_directive() { let tag_directive = YamlTagDirectiveT::default(); assert!(tag_directive.handle.is_null()); assert!(tag_directive.prefix.is_null()); } /// Tests the default values of YamlBreakT #[test] fn test_default_yaml_break() { let line_break = YamlBreakT::default(); assert_eq!(line_break, YamlBreakT::YamlAnyBreak); } /// Tests the default values of YamlErrorTypeT #[test] fn test_default_yaml_error_type() { let error_type = YamlErrorTypeT::default(); assert_eq!(error_type, YamlErrorTypeT::YamlNoError); } /// Tests the default values of YamlSimpleKeyT #[test] fn test_default_yaml_simple_key() { let simple_key = YamlSimpleKeyT::default(); assert!(!simple_key.possible); assert!(!simple_key.required); assert_eq!(simple_key.token_number, 0); assert_eq!(simple_key.mark.index, 0); assert_eq!(simple_key.mark.line, 0); assert_eq!(simple_key.mark.column, 0); } /// Tests the default values of YamlEventTypeT #[test] fn test_default_yaml_event_type() { let event_type = YamlEventTypeT::default(); assert_eq!(event_type, YamlEventTypeT::YamlNoEvent); } /// Tests the default values of YamlNodeTypeT #[test] fn test_default_yaml_node_type() { let node_type = YamlNodeTypeT::default(); assert_eq!(node_type, YamlNodeTypeT::YamlNoNode); } /// Tests the default values of YamlParserStateT #[test] fn test_default_yaml_parser_state() { let parser_state = YamlParserStateT::default(); assert_eq!( parser_state, YamlParserStateT::YamlParseStreamStartState ); } /// Tests the default values of YamlAliasDataT #[test] fn test_default_yaml_anchor_data() { let anchor_data = YamlAliasDataT::default(); assert!(anchor_data.anchor.is_null()); assert_eq!(anchor_data.index, 0); assert_eq!(anchor_data.mark.index, 0); assert_eq!(anchor_data.mark.line, 0); assert_eq!(anchor_data.mark.column, 0); } /// Tests the default values of YamlTokenT #[test] fn test_default_yaml_token() { let token = YamlTokenT::default(); assert_eq!(token.type_, YamlTokenTypeT::YamlNoToken); assert_eq!(token.start_mark.index, 0); assert_eq!(token.start_mark.line, 0); assert_eq!(token.start_mark.column, 0); assert_eq!(token.end_mark.index, 0); assert_eq!(token.end_mark.line, 0); assert_eq!(token.end_mark.column, 0); } /// Tests the default values of YamlEmitterStateT #[test] fn test_default_yaml_emitter_state() { let emitter_state = YamlEmitterStateT::default(); assert_eq!( emitter_state, YamlEmitterStateT::YamlEmitStreamStartState ); } // Enum value tests /// Tests the values of YamlEncodingT enum variants #[test] fn test_yaml_encoding_values() { assert_eq!(YamlEncodingT::YamlAnyEncoding as u32, 0); assert_eq!(YamlEncodingT::YamlUtf8Encoding as u32, 1); assert_eq!(YamlEncodingT::YamlUtf16leEncoding as u32, 2); assert_eq!(YamlEncodingT::YamlUtf16beEncoding as u32, 3); } /// Tests the values of YamlEventTypeT enum variants #[test] fn test_yaml_event_type_values() { assert_eq!(YamlEventTypeT::YamlNoEvent as u32, 0); assert_eq!(YamlEventTypeT::YamlStreamStartEvent as u32, 1); assert_eq!(YamlEventTypeT::YamlStreamEndEvent as u32, 2); assert_eq!(YamlEventTypeT::YamlDocumentStartEvent as u32, 3); assert_eq!(YamlEventTypeT::YamlDocumentEndEvent as u32, 4); assert_eq!(YamlEventTypeT::YamlAliasEvent as u32, 5); assert_eq!(YamlEventTypeT::YamlScalarEvent as u32, 6); assert_eq!(YamlEventTypeT::YamlSequenceStartEvent as u32, 7); assert_eq!(YamlEventTypeT::YamlSequenceEndEvent as u32, 8); assert_eq!(YamlEventTypeT::YamlMappingStartEvent as u32, 9); assert_eq!(YamlEventTypeT::YamlMappingEndEvent as u32, 10); } /// Tests the values of YamlScalarStyleT enum variants #[test] fn test_yaml_scalar_style_values() { assert_eq!(YamlScalarStyleT::YamlAnyScalarStyle as u32, 0); assert_eq!(YamlScalarStyleT::YamlPlainScalarStyle as u32, 1); assert_eq!(YamlScalarStyleT::YamlSingleQuotedScalarStyle as u32, 2); assert_eq!(YamlScalarStyleT::YamlDoubleQuotedScalarStyle as u32, 3); assert_eq!(YamlScalarStyleT::YamlLiteralScalarStyle as u32, 4); assert_eq!(YamlScalarStyleT::YamlFoldedScalarStyle as u32, 5); } /// Tests the values of YamlSequenceStyleT enum variants #[test] fn test_yaml_sequence_style_values() { assert_eq!(YamlSequenceStyleT::YamlAnySequenceStyle as u32, 0); assert_eq!(YamlSequenceStyleT::YamlBlockSequenceStyle as u32, 1); assert_eq!(YamlSequenceStyleT::YamlFlowSequenceStyle as u32, 2); } /// Tests the values of YamlMappingStyleT enum variants #[test] fn test_yaml_mapping_style_values() { assert_eq!(YamlMappingStyleT::YamlAnyMappingStyle as u32, 0); assert_eq!(YamlMappingStyleT::YamlBlockMappingStyle as u32, 1); assert_eq!(YamlMappingStyleT::YamlFlowMappingStyle as u32, 2); } /// Tests the values of YamlErrorTypeT enum variants #[test] fn test_yaml_error_type_values() { assert_eq!(YamlErrorTypeT::YamlNoError as u32, 0); assert_eq!(YamlErrorTypeT::YamlMemoryError as u32, 1); assert_eq!(YamlErrorTypeT::YamlReaderError as u32, 2); assert_eq!(YamlErrorTypeT::YamlScannerError as u32, 3); assert_eq!(YamlErrorTypeT::YamlParserError as u32, 4); assert_eq!(YamlErrorTypeT::YamlComposerError as u32, 5); assert_eq!(YamlErrorTypeT::YamlWriterError as u32, 6); assert_eq!(YamlErrorTypeT::YamlEmitterError as u32, 7); } /// Tests the values of YamlNodeTypeT enum variants #[test] fn test_yaml_node_type_values() { assert_eq!(YamlNodeTypeT::YamlNoNode as u32, 0); assert_eq!(YamlNodeTypeT::YamlScalarNode as u32, 1); assert_eq!(YamlNodeTypeT::YamlSequenceNode as u32, 2); assert_eq!(YamlNodeTypeT::YamlMappingNode as u32, 3); } /// Tests the values of YamlBreakT enum variants #[test] fn test_yaml_break_type_values() { assert_eq!(YamlBreakT::YamlAnyBreak as u32, 0); assert_eq!(YamlBreakT::YamlCrBreak as u32, 1); assert_eq!(YamlBreakT::YamlLnBreak as u32, 2); assert_eq!(YamlBreakT::YamlCrlnBreak as u32, 3); } /// Tests the values of YamlParserStateT enum variants #[test] fn test_yaml_parser_state_values() { assert_eq!(YamlParserStateT::YamlParseStreamStartState as u32, 0); assert_eq!( YamlParserStateT::YamlParseImplicitDocumentStartState as u32, 1 ); assert_eq!(YamlParserStateT::YamlParseDocumentStartState as u32, 2); assert_eq!( YamlParserStateT::YamlParseDocumentContentState as u32, 3 ); assert_eq!(YamlParserStateT::YamlParseDocumentEndState as u32, 4); assert_eq!(YamlParserStateT::YamlParseBlockNodeState as u32, 5); assert_eq!( YamlParserStateT::YamlParseBlockNodeOrIndentlessSequenceState as u32, 6 ); assert_eq!(YamlParserStateT::YamlParseFlowNodeState as u32, 7); assert_eq!( YamlParserStateT::YamlParseBlockSequenceFirstEntryState as u32, 8 ); assert_eq!( YamlParserStateT::YamlParseBlockSequenceEntryState as u32, 9 ); assert_eq!( YamlParserStateT::YamlParseIndentlessSequenceEntryState as u32, 10 ); assert_eq!( YamlParserStateT::YamlParseBlockMappingFirstKeyState as u32, 11 ); assert_eq!( YamlParserStateT::YamlParseBlockMappingKeyState as u32, 12 ); assert_eq!( YamlParserStateT::YamlParseBlockMappingValueState as u32, 13 ); assert_eq!( YamlParserStateT::YamlParseFlowSequenceFirstEntryState as u32, 14 ); assert_eq!( YamlParserStateT::YamlParseFlowSequenceEntryState as u32, 15 ); assert_eq!( YamlParserStateT::YamlParseFlowSequenceEntryMappingKeyState as u32, 16 ); assert_eq!( YamlParserStateT::YamlParseFlowSequenceEntryMappingValueState as u32, 17 ); assert_eq!( YamlParserStateT::YamlParseFlowSequenceEntryMappingEndState as u32, 18 ); assert_eq!( YamlParserStateT::YamlParseFlowMappingFirstKeyState as u32, 19 ); assert_eq!( YamlParserStateT::YamlParseFlowMappingKeyState as u32, 20 ); assert_eq!( YamlParserStateT::YamlParseFlowMappingValueState as u32, 21 ); assert_eq!( YamlParserStateT::YamlParseFlowMappingEmptyValueState as u32, 22 ); assert_eq!(YamlParserStateT::YamlParseEndState as u32, 23); } /// Tests the values of YamlEmitterStateT enum variants #[test] fn test_yaml_emitter_state_values() { assert_eq!(YamlEmitterStateT::YamlEmitStreamStartState as u32, 0); assert_eq!( YamlEmitterStateT::YamlEmitFirstDocumentStartState as u32, 1 ); assert_eq!(YamlEmitterStateT::YamlEmitDocumentStartState as u32, 2); assert_eq!( YamlEmitterStateT::YamlEmitDocumentContentState as u32, 3 ); assert_eq!(YamlEmitterStateT::YamlEmitDocumentEndState as u32, 4); assert_eq!( YamlEmitterStateT::YamlEmitFlowSequenceFirstItemState as u32, 5 ); assert_eq!( YamlEmitterStateT::YamlEmitFlowSequenceItemState as u32, 6 ); assert_eq!( YamlEmitterStateT::YamlEmitFlowMappingFirstKeyState as u32, 7 ); assert_eq!( YamlEmitterStateT::YamlEmitFlowMappingKeyState as u32, 8 ); assert_eq!( YamlEmitterStateT::YamlEmitFlowMappingSimpleValueState as u32, 9 ); assert_eq!( YamlEmitterStateT::YamlEmitFlowMappingValueState as u32, 10 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockSequenceFirstItemState as u32, 11 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockSequenceItemState as u32, 12 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockMappingFirstKeyState as u32, 13 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockMappingKeyState as u32, 14 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockMappingSimpleValueState as u32, 15 ); assert_eq!( YamlEmitterStateT::YamlEmitBlockMappingValueState as u32, 16 ); assert_eq!(YamlEmitterStateT::YamlEmitEndState as u32, 17); } /// Tests the constructor of YamlVersionDirectiveT #[test] fn test_yaml_version_directive() { let version_directive = YamlVersionDirectiveT::new(1, 2); assert_eq!(version_directive.major, 1); assert_eq!(version_directive.minor, 2); }