Skip to main content

unsafe_libyaml/
dumper.rs

1use core::{
2    mem::{MaybeUninit, size_of},
3    ptr::{self, addr_of_mut},
4};
5
6use crate::{
7    PointerExt,
8    api::{yaml_free, yaml_malloc},
9    externs::{memset, strcmp},
10    fmt::WriteToPtr,
11    libc,
12    ops::ForceMul as _,
13    success::{FAIL, OK, Success},
14    yaml::{
15        YAML_ALIAS_EVENT, YAML_ANY_ENCODING, YAML_DOCUMENT_END_EVENT, YAML_DOCUMENT_START_EVENT,
16        YAML_MAPPING_END_EVENT, YAML_MAPPING_NODE, YAML_MAPPING_START_EVENT, YAML_SCALAR_EVENT, YAML_SCALAR_NODE,
17        YAML_SEQUENCE_END_EVENT, YAML_SEQUENCE_NODE, YAML_SEQUENCE_START_EVENT, YAML_STREAM_END_EVENT,
18        YAML_STREAM_START_EVENT, yaml_anchors_t, yaml_char_t, yaml_document_t, yaml_emitter_t, yaml_event_t,
19        yaml_mark_t, yaml_node_item_t, yaml_node_pair_t, yaml_node_t,
20    },
21    yaml_document_delete, yaml_emitter_emit,
22};
23
24/// Start a YAML stream.
25///
26/// This function should be used before yaml_emitter_dump() is called.
27pub unsafe fn yaml_emitter_open(emitter: *mut yaml_emitter_t) -> Success {
28    let mut event = MaybeUninit::<yaml_event_t>::uninit();
29    let event = event.as_mut_ptr();
30    let mark = yaml_mark_t {
31        index: 0_u64,
32        line: 0_u64,
33        column: 0_u64,
34    };
35    __assert!(!emitter.is_null());
36    __assert!(!(*emitter).opened);
37    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
38    (*event).type_ = YAML_STREAM_START_EVENT;
39    (*event).start_mark = mark;
40    (*event).end_mark = mark;
41    (*event).data.stream_start.encoding = YAML_ANY_ENCODING;
42    if yaml_emitter_emit(emitter, event).fail {
43        return FAIL;
44    }
45    (*emitter).opened = true;
46    OK
47}
48
49/// Finish a YAML stream.
50///
51/// This function should be used after yaml_emitter_dump() is called.
52pub unsafe fn yaml_emitter_close(emitter: *mut yaml_emitter_t) -> Success {
53    let mut event = MaybeUninit::<yaml_event_t>::uninit();
54    let event = event.as_mut_ptr();
55    let mark = yaml_mark_t {
56        index: 0_u64,
57        line: 0_u64,
58        column: 0_u64,
59    };
60    __assert!(!emitter.is_null());
61    __assert!((*emitter).opened);
62    if (*emitter).closed {
63        return OK;
64    }
65    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
66    (*event).type_ = YAML_STREAM_END_EVENT;
67    (*event).start_mark = mark;
68    (*event).end_mark = mark;
69    if yaml_emitter_emit(emitter, event).fail {
70        return FAIL;
71    }
72    (*emitter).closed = true;
73    OK
74}
75
76/// Emit a YAML document.
77///
78/// The document object may be generated using the yaml_parser_load() function or
79/// the yaml_document_initialize() function. The emitter takes the
80/// responsibility for the document object and destroys its content after it is
81/// emitted. The document object is destroyed even if the function fails.
82pub unsafe fn yaml_emitter_dump(emitter: *mut yaml_emitter_t, document: *mut yaml_document_t) -> Success {
83    let current_block: u64;
84    let mut event = MaybeUninit::<yaml_event_t>::uninit();
85    let event = event.as_mut_ptr();
86    let mark = yaml_mark_t {
87        index: 0_u64,
88        line: 0_u64,
89        column: 0_u64,
90    };
91    __assert!(!emitter.is_null());
92    __assert!(!document.is_null());
93    let fresh0 = addr_of_mut!((*emitter).document);
94    *fresh0 = document;
95    if !(*emitter).opened {
96        if yaml_emitter_open(emitter).fail {
97            current_block = 5018439318894558507;
98        } else {
99            current_block = 15619007995458559411;
100        }
101    } else {
102        current_block = 15619007995458559411;
103    }
104    match current_block {
105        15619007995458559411 => {
106            if STACK_EMPTY!((*document).nodes) {
107                if yaml_emitter_close(emitter).ok {
108                    yaml_emitter_delete_document_and_anchors(emitter);
109                    return OK;
110                }
111            } else {
112                __assert!((*emitter).opened);
113                let fresh1 = addr_of_mut!((*emitter).anchors);
114                *fresh1 = yaml_malloc(
115                    (size_of::<yaml_anchors_t>() as libc::c_ulong)
116                        .force_mul((*document).nodes.top.c_offset_from((*document).nodes.start) as libc::c_ulong),
117                ) as *mut yaml_anchors_t;
118                memset(
119                    (*emitter).anchors as *mut libc::c_void,
120                    0,
121                    (size_of::<yaml_anchors_t>() as libc::c_ulong)
122                        .force_mul((*document).nodes.top.c_offset_from((*document).nodes.start) as libc::c_ulong),
123                );
124                memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
125                (*event).type_ = YAML_DOCUMENT_START_EVENT;
126                (*event).start_mark = mark;
127                (*event).end_mark = mark;
128                (*event).data.document_start.version_directive = (*document).version_directive;
129                (*event).data.document_start.tag_directives.start = (*document).tag_directives.start;
130                (*event).data.document_start.tag_directives.end = (*document).tag_directives.end;
131                (*event).data.document_start.implicit = (*document).start_implicit;
132                if yaml_emitter_emit(emitter, event).ok {
133                    yaml_emitter_anchor_node(emitter, 1);
134                    if yaml_emitter_dump_node(emitter, 1).ok {
135                        memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
136                        (*event).type_ = YAML_DOCUMENT_END_EVENT;
137                        (*event).start_mark = mark;
138                        (*event).end_mark = mark;
139                        (*event).data.document_end.implicit = (*document).end_implicit;
140                        if yaml_emitter_emit(emitter, event).ok {
141                            yaml_emitter_delete_document_and_anchors(emitter);
142                            return OK;
143                        }
144                    }
145                }
146            }
147        }
148        _ => {}
149    }
150    yaml_emitter_delete_document_and_anchors(emitter);
151    FAIL
152}
153
154unsafe fn yaml_emitter_delete_document_and_anchors(emitter: *mut yaml_emitter_t) {
155    let mut index: libc::c_int;
156    if (*emitter).anchors.is_null() {
157        yaml_document_delete((*emitter).document);
158        let fresh2 = addr_of_mut!((*emitter).document);
159        *fresh2 = ptr::null_mut::<yaml_document_t>();
160        return;
161    }
162    index = 0;
163    while (*(*emitter).document).nodes.start.wrapping_offset(index as isize) < (*(*emitter).document).nodes.top {
164        let mut node: yaml_node_t = *(*(*emitter).document).nodes.start.wrapping_offset(index as isize);
165        if !(*(*emitter).anchors.wrapping_offset(index as isize)).serialized {
166            yaml_free(node.tag as *mut libc::c_void);
167            if node.type_ == YAML_SCALAR_NODE {
168                yaml_free(node.data.scalar.value as *mut libc::c_void);
169            }
170        }
171        if node.type_ == YAML_SEQUENCE_NODE {
172            STACK_DEL!(node.data.sequence.items);
173        }
174        if node.type_ == YAML_MAPPING_NODE {
175            STACK_DEL!(node.data.mapping.pairs);
176        }
177        index += 1;
178    }
179    STACK_DEL!((*(*emitter).document).nodes);
180    yaml_free((*emitter).anchors as *mut libc::c_void);
181    let fresh6 = addr_of_mut!((*emitter).anchors);
182    *fresh6 = ptr::null_mut::<yaml_anchors_t>();
183    (*emitter).last_anchor_id = 0;
184    let fresh7 = addr_of_mut!((*emitter).document);
185    *fresh7 = ptr::null_mut::<yaml_document_t>();
186}
187
188unsafe fn yaml_emitter_anchor_node_sub(emitter: *mut yaml_emitter_t, index: libc::c_int) {
189    (*((*emitter).anchors).offset((index - 1) as isize)).references += 1;
190    if (*(*emitter).anchors.offset((index - 1) as isize)).references == 2 {
191        (*emitter).last_anchor_id += 1;
192        (*(*emitter).anchors.offset((index - 1) as isize)).anchor = (*emitter).last_anchor_id;
193    }
194}
195
196unsafe fn yaml_emitter_anchor_node(emitter: *mut yaml_emitter_t, index: libc::c_int) {
197    let node: *mut yaml_node_t = (*(*emitter).document)
198        .nodes
199        .start
200        .wrapping_offset(index as isize)
201        .wrapping_offset(-1_isize);
202    let mut item: *mut yaml_node_item_t;
203    let mut pair: *mut yaml_node_pair_t;
204    let fresh8 = addr_of_mut!((*((*emitter).anchors).wrapping_offset((index - 1) as isize)).references);
205    *fresh8 += 1;
206    if (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).references == 1 {
207        match (*node).type_ {
208            YAML_SEQUENCE_NODE => {
209                item = (*node).data.sequence.items.start;
210                while item < (*node).data.sequence.items.top {
211                    yaml_emitter_anchor_node_sub(emitter, *item);
212                    item = item.wrapping_offset(1);
213                }
214            }
215            YAML_MAPPING_NODE => {
216                pair = (*node).data.mapping.pairs.start;
217                while pair < (*node).data.mapping.pairs.top {
218                    yaml_emitter_anchor_node_sub(emitter, (*pair).key);
219                    yaml_emitter_anchor_node_sub(emitter, (*pair).value);
220                    pair = pair.wrapping_offset(1);
221                }
222            }
223            _ => {}
224        }
225    } else if (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).references == 2 {
226        let fresh9 = addr_of_mut!((*emitter).last_anchor_id);
227        *fresh9 += 1;
228        (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).anchor = *fresh9;
229    }
230}
231
232unsafe fn yaml_emitter_generate_anchor(_emitter: *mut yaml_emitter_t, anchor_id: libc::c_int) -> *mut yaml_char_t {
233    let anchor: *mut yaml_char_t = yaml_malloc(16_u64) as *mut yaml_char_t;
234    write!(WriteToPtr::new(anchor), "id{:03}\0", anchor_id);
235    anchor
236}
237
238unsafe fn yaml_emitter_dump_node(emitter: *mut yaml_emitter_t, index: libc::c_int) -> Success {
239    let node: *mut yaml_node_t = (*(*emitter).document)
240        .nodes
241        .start
242        .wrapping_offset(index as isize)
243        .wrapping_offset(-1_isize);
244    let anchor_id: libc::c_int = (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).anchor;
245    let mut anchor: *mut yaml_char_t = ptr::null_mut::<yaml_char_t>();
246    if anchor_id != 0 {
247        anchor = yaml_emitter_generate_anchor(emitter, anchor_id);
248    }
249    if (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).serialized {
250        return yaml_emitter_dump_alias(emitter, anchor);
251    }
252    (*(*emitter).anchors.wrapping_offset((index - 1) as isize)).serialized = true;
253    match (*node).type_ {
254        YAML_SCALAR_NODE => yaml_emitter_dump_scalar(emitter, node, anchor),
255        YAML_SEQUENCE_NODE => yaml_emitter_dump_sequence(emitter, node, anchor),
256        YAML_MAPPING_NODE => yaml_emitter_dump_mapping(emitter, node, anchor),
257        _ => __assert!(false),
258    }
259}
260
261unsafe fn yaml_emitter_dump_alias(emitter: *mut yaml_emitter_t, anchor: *mut yaml_char_t) -> Success {
262    let mut event = MaybeUninit::<yaml_event_t>::uninit();
263    let event = event.as_mut_ptr();
264    let mark = yaml_mark_t {
265        index: 0_u64,
266        line: 0_u64,
267        column: 0_u64,
268    };
269    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
270    (*event).type_ = YAML_ALIAS_EVENT;
271    (*event).start_mark = mark;
272    (*event).end_mark = mark;
273    (*event).data.alias.anchor = anchor;
274    yaml_emitter_emit(emitter, event)
275}
276
277unsafe fn yaml_emitter_dump_scalar(
278    emitter: *mut yaml_emitter_t,
279    node: *mut yaml_node_t,
280    anchor: *mut yaml_char_t,
281) -> Success {
282    let mut event = MaybeUninit::<yaml_event_t>::uninit();
283    let event = event.as_mut_ptr();
284    let mark = yaml_mark_t {
285        index: 0_u64,
286        line: 0_u64,
287        column: 0_u64,
288    };
289    let plain_implicit = strcmp(
290        (*node).tag as *mut libc::c_char,
291        b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char,
292    ) == 0;
293    let quoted_implicit = strcmp(
294        (*node).tag as *mut libc::c_char,
295        b"tag:yaml.org,2002:str\0" as *const u8 as *const libc::c_char,
296    ) == 0;
297    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
298    (*event).type_ = YAML_SCALAR_EVENT;
299    (*event).start_mark = mark;
300    (*event).end_mark = mark;
301    (*event).data.scalar.anchor = anchor;
302    (*event).data.scalar.tag = (*node).tag;
303    (*event).data.scalar.value = (*node).data.scalar.value;
304    (*event).data.scalar.length = (*node).data.scalar.length;
305    (*event).data.scalar.plain_implicit = plain_implicit;
306    (*event).data.scalar.quoted_implicit = quoted_implicit;
307    (*event).data.scalar.style = (*node).data.scalar.style;
308    yaml_emitter_emit(emitter, event)
309}
310
311unsafe fn yaml_emitter_dump_sequence(
312    emitter: *mut yaml_emitter_t,
313    node: *mut yaml_node_t,
314    anchor: *mut yaml_char_t,
315) -> Success {
316    let mut event = MaybeUninit::<yaml_event_t>::uninit();
317    let event = event.as_mut_ptr();
318    let mark = yaml_mark_t {
319        index: 0_u64,
320        line: 0_u64,
321        column: 0_u64,
322    };
323    let implicit = strcmp(
324        (*node).tag as *mut libc::c_char,
325        b"tag:yaml.org,2002:seq\0" as *const u8 as *const libc::c_char,
326    ) == 0;
327    let mut item: *mut yaml_node_item_t;
328    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
329    (*event).type_ = YAML_SEQUENCE_START_EVENT;
330    (*event).start_mark = mark;
331    (*event).end_mark = mark;
332    (*event).data.sequence_start.anchor = anchor;
333    (*event).data.sequence_start.tag = (*node).tag;
334    (*event).data.sequence_start.implicit = implicit;
335    (*event).data.sequence_start.style = (*node).data.sequence.style;
336    if yaml_emitter_emit(emitter, event).fail {
337        return FAIL;
338    }
339    item = (*node).data.sequence.items.start;
340    while item < (*node).data.sequence.items.top {
341        if yaml_emitter_dump_node(emitter, *item).fail {
342            return FAIL;
343        }
344        item = item.wrapping_offset(1);
345    }
346    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
347    (*event).type_ = YAML_SEQUENCE_END_EVENT;
348    (*event).start_mark = mark;
349    (*event).end_mark = mark;
350    yaml_emitter_emit(emitter, event)
351}
352
353unsafe fn yaml_emitter_dump_mapping(
354    emitter: *mut yaml_emitter_t,
355    node: *mut yaml_node_t,
356    anchor: *mut yaml_char_t,
357) -> Success {
358    let mut event = MaybeUninit::<yaml_event_t>::uninit();
359    let event = event.as_mut_ptr();
360    let mark = yaml_mark_t {
361        index: 0_u64,
362        line: 0_u64,
363        column: 0_u64,
364    };
365    let implicit = strcmp(
366        (*node).tag as *mut libc::c_char,
367        b"tag:yaml.org,2002:map\0" as *const u8 as *const libc::c_char,
368    ) == 0;
369    let mut pair: *mut yaml_node_pair_t;
370    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
371    (*event).type_ = YAML_MAPPING_START_EVENT;
372    (*event).start_mark = mark;
373    (*event).end_mark = mark;
374    (*event).data.mapping_start.anchor = anchor;
375    (*event).data.mapping_start.tag = (*node).tag;
376    (*event).data.mapping_start.implicit = implicit;
377    (*event).data.mapping_start.style = (*node).data.mapping.style;
378    if yaml_emitter_emit(emitter, event).fail {
379        return FAIL;
380    }
381    pair = (*node).data.mapping.pairs.start;
382    while pair < (*node).data.mapping.pairs.top {
383        if yaml_emitter_dump_node(emitter, (*pair).key).fail {
384            return FAIL;
385        }
386        if yaml_emitter_dump_node(emitter, (*pair).value).fail {
387            return FAIL;
388        }
389        pair = pair.wrapping_offset(1);
390    }
391    memset(event as *mut libc::c_void, 0, size_of::<yaml_event_t>() as libc::c_ulong);
392    (*event).type_ = YAML_MAPPING_END_EVENT;
393    (*event).start_mark = mark;
394    (*event).end_mark = mark;
395    yaml_emitter_emit(emitter, event)
396}