1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use 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
}