fyrox_impl/resource/fbx/document/
ascii.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::core::byteorder::ReadBytesExt;
22use crate::{
23    core::pool::{Handle, Pool},
24    resource::fbx::{
25        document::{attribute::FbxAttribute, FbxDocument, FbxNode, FbxNodeContainer},
26        error::FbxError,
27    },
28};
29use std::io::{Read, Seek, SeekFrom};
30
31pub fn read_ascii<R>(reader: &mut R) -> Result<FbxDocument, FbxError>
32where
33    R: Read + Seek,
34{
35    let mut nodes: Pool<FbxNode> = Pool::new();
36    let root_handle = nodes.spawn(FbxNode {
37        name: String::from("__ROOT__"),
38        children: Vec::new(),
39        parent: Handle::NONE,
40        attributes: Vec::new(),
41    });
42    let mut parent_handle: Handle<FbxNode> = root_handle;
43    let mut node_handle: Handle<FbxNode> = Handle::NONE;
44    let mut buffer: Vec<u8> = Vec::new();
45    let mut name: Vec<u8> = Vec::new();
46    let mut value: Vec<u8> = Vec::new();
47
48    let buf_len = reader.seek(SeekFrom::End(0))?;
49    reader.rewind()?;
50
51    // Read line by line
52    while reader.stream_position()? < buf_len {
53        // Read line, trim spaces (but leave spaces in quotes)
54        buffer.clear();
55
56        let mut read_all = false;
57        while reader.stream_position()? < buf_len {
58            let symbol = reader.read_u8()?;
59            if symbol == b'\n' {
60                break;
61            } else if symbol == b'"' {
62                read_all = !read_all;
63            } else if read_all || !symbol.is_ascii_whitespace() {
64                buffer.push(symbol);
65            }
66        }
67
68        // Ignore comments and empty lines
69        if buffer.is_empty() || buffer[0] == b';' {
70            continue;
71        }
72
73        // Parse string
74        let mut read_value = false;
75        name.clear();
76        for (i, symbol) in buffer.iter().enumerate() {
77            let symbol = *symbol;
78            if i == 0 && (symbol == b'-' || symbol.is_ascii_digit()) {
79                read_value = true;
80            }
81            if symbol == b':' && !read_value {
82                read_value = true;
83                let name_copy = String::from_utf8(name.clone())?;
84                let node = FbxNode {
85                    name: name_copy,
86                    attributes: Vec::new(),
87                    parent: parent_handle,
88                    children: Vec::new(),
89                };
90                node_handle = nodes.spawn(node);
91                name.clear();
92                let parent = nodes.borrow_mut(parent_handle);
93                parent.children.push(node_handle);
94            } else if symbol == b'{' {
95                // Enter child scope
96                parent_handle = node_handle;
97                // Commit attribute if we have one
98                if !value.is_empty() {
99                    let node = nodes.borrow_mut(node_handle);
100                    let string_value = String::from_utf8(value.clone())?;
101                    let attrib = FbxAttribute::String(string_value);
102                    node.attributes.push(attrib);
103                    value.clear();
104                }
105            } else if symbol == b'}' {
106                // Exit child scope
107                let parent = nodes.borrow_mut(parent_handle);
108                parent_handle = parent.parent;
109            } else if symbol == b',' || (i == buffer.len() - 1) {
110                // Commit attribute
111                if symbol != b',' {
112                    value.push(symbol);
113                }
114                let node = nodes.borrow_mut(node_handle);
115                let string_value = String::from_utf8(value.clone())?;
116                let attrib = FbxAttribute::String(string_value);
117                node.attributes.push(attrib);
118                value.clear();
119            } else if !read_value {
120                name.push(symbol);
121            } else {
122                value.push(symbol);
123            }
124        }
125    }
126
127    Ok(FbxDocument {
128        nodes: FbxNodeContainer { nodes },
129        root: root_handle,
130    })
131}