assembly_data/xml/database/
mod.rs

1//! # The XML `<database>` format
2//!
3//! Before the FDB file format was created, older versions of the client used an XML
4//! file to store the client database. This was also used for LUPs to add their data
5//! independently of the rest of the game.
6
7use assembly_core::displaydoc::Display;
8use quick_xml::{events::Event, Reader};
9use std::{collections::HashMap, error::Error, fmt, io::BufRead, str::FromStr};
10
11use super::common::{expect_elem, expect_named_elem, XmlError};
12
13#[cfg(feature = "serde-derives")]
14use serde::{
15    de::{self, Unexpected, Visitor},
16    Deserialize, Deserializer,
17};
18
19/// The value types for the database
20///
21/// This is a rustic representation of the data types in Transact-SQL that
22/// were/are used in the database.
23///
24/// See: <https://docs.microsoft.com/en-us/sql/t-sql/data-types>
25#[derive(Debug, Copy, Clone, PartialEq, Eq)]
26pub enum ValueType {
27    /// `bit`
28    Bit,
29
30    /// `float`
31    Float,
32    /// `real`
33    Real,
34
35    /// `int`
36    Int,
37    /// `bigint`
38    BigInt,
39    /// `smallint`
40    SmallInt,
41    /// `tinyint`
42    TinyInt,
43
44    /// `binary`
45    Binary,
46    /// `varbinary`
47    VarBinary,
48
49    /// `char`
50    Char,
51    /// `varchar`
52    VarChar,
53
54    /// `nchar`
55    NChar,
56    /// `nvarchar`
57    NVarChar,
58
59    /// `ntext`
60    NText,
61    /// `text`
62    Text,
63    /// `image`
64    Image,
65
66    /// `datetime`
67    DateTime,
68}
69
70impl<'de> Deserialize<'de> for ValueType {
71    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72    where
73        D: Deserializer<'de>,
74    {
75        deserializer.deserialize_str(ValueTypeVisitor)
76    }
77}
78
79#[derive(Debug, Display)]
80/// Unknown value type '{0}'
81pub struct UnknownValueType(String);
82
83impl Error for UnknownValueType {}
84
85impl FromStr for ValueType {
86    type Err = UnknownValueType;
87
88    fn from_str(s: &str) -> Result<Self, Self::Err> {
89        match s {
90            "bit" => Ok(Self::Bit),
91
92            "float" => Ok(Self::Float),
93            "real" => Ok(Self::Real),
94
95            "int" => Ok(Self::Int),
96            "bigint" => Ok(Self::BigInt),
97            "smallint" => Ok(Self::SmallInt),
98            "tinyint" => Ok(Self::TinyInt),
99
100            "binary" => Ok(Self::Binary),
101            "varbinary" => Ok(Self::VarBinary),
102
103            "char" => Ok(Self::Char),
104            "varchar" => Ok(Self::VarChar),
105
106            "nchar" => Ok(Self::NChar),
107            "nvarchar" => Ok(Self::NVarChar),
108
109            "text" => Ok(Self::Text),
110            "ntext" => Ok(Self::NText),
111            "image" => Ok(Self::Image),
112
113            "datetime" => Ok(Self::DateTime),
114
115            _ => Err(UnknownValueType(s.to_owned())),
116        }
117    }
118}
119
120#[cfg(feature = "serde-derives")]
121struct ValueTypeVisitor;
122
123#[cfg(feature = "serde-derives")]
124impl<'de> Visitor<'de> for ValueTypeVisitor {
125    type Value = ValueType;
126
127    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
128        formatter.write_str("T-SQL value type")
129    }
130
131    fn visit_str<E>(self, value: &str) -> Result<ValueType, E>
132    where
133        E: de::Error,
134    {
135        FromStr::from_str(value)
136            .map_err(|_| E::invalid_value(Unexpected::Other(value), &"T-SQL value type"))
137    }
138}
139
140/// A row of the database
141#[cfg_attr(feature = "serde-derives", derive(Deserialize))]
142#[derive(Debug, Eq, PartialEq)]
143pub struct Row(HashMap<String, String>);
144
145/// Expects an opening `<database>`
146pub fn expect_database<B: BufRead>(
147    xml: &mut Reader<B>,
148    buf: &mut Vec<u8>,
149) -> Result<Option<String>, XmlError> {
150    expect_named_elem(xml, buf, "database", None)
151}
152
153/// Expects an opening `<table>` tag or a closing `</database>` tag
154pub fn expect_table<B: BufRead>(
155    xml: &mut Reader<B>,
156    buf: &mut Vec<u8>,
157) -> Result<Option<String>, XmlError> {
158    expect_named_elem(xml, buf, "table", Some("database"))
159}
160
161/// Expects an opening `<columns>` tag
162pub fn expect_columns<B: BufRead>(xml: &mut Reader<B>, buf: &mut Vec<u8>) -> Result<(), XmlError> {
163    expect_elem(xml, buf, "columns")
164}
165
166/// Expects an opening `<rows>` tag
167pub fn expect_rows<B: BufRead>(xml: &mut Reader<B>, buf: &mut Vec<u8>) -> Result<(), XmlError> {
168    expect_elem(xml, buf, "rows")
169}
170
171/// The information on a column
172#[cfg_attr(feature = "serde-derives", derive(Deserialize))]
173pub struct Column {
174    /// The name of the column
175    pub name: String,
176    /// The data type of the column
177    pub r#type: ValueType,
178}
179
180/*#[derive(Deserialize)]
181/// The Columns struct
182pub struct Columns {
183    /// The columns
184    columns: Vec<Column>
185}*/
186
187/// Expects an empty `<column …/>` tag or a closing `</columns>` tag
188pub fn expect_column_or_end_columns<B: BufRead>(
189    xml: &mut Reader<B>,
190    buf: &mut Vec<u8>,
191) -> Result<Option<Column>, XmlError> {
192    match xml.read_event(buf)? {
193        Event::Empty(start) => {
194            if start.name() == b"column" {
195                let mut name = None;
196                let mut data_type = None;
197                for attr in start.attributes() {
198                    let attr = attr?;
199                    if attr.key == b"name" {
200                        name = Some(xml.decode(&attr.value).into_owned());
201                    }
202
203                    if attr.key == b"type" {
204                        data_type = Some(
205                            xml.decode(&attr.value)
206                                .parse()
207                                .expect("Expected well-known value type"),
208                        );
209                    }
210                }
211                buf.clear();
212                Ok(Some(Column {
213                    name: name.unwrap(),
214                    r#type: data_type.unwrap(),
215                }))
216            } else {
217                todo!();
218            }
219        }
220        Event::End(v) => {
221            assert_eq!(v.name(), b"columns");
222            Ok(None)
223        }
224        Event::Eof => Err(XmlError::EofWhileExpecting("column")),
225        x => panic!("What? {:?}", x),
226    }
227}
228
229/// Expects an empty `<row …/>` tag or a closing `</rows>` tag
230pub fn expect_row_or_end_rows<B: BufRead>(
231    xml: &mut Reader<B>,
232    buf: &mut Vec<u8>,
233    load_attrs: bool,
234) -> Result<Option<HashMap<String, String>>, XmlError> {
235    match xml.read_event(buf)? {
236        Event::Empty(start) => {
237            if start.name() == b"row" {
238                let map = if load_attrs {
239                    let mut m = HashMap::new();
240                    for attr in start.attributes() {
241                        let attr = attr?;
242                        let key = xml.decode(attr.key).into_owned();
243                        let value = attr.unescape_and_decode_value(xml)?;
244                        m.insert(key, value);
245                    }
246                    m
247                } else {
248                    HashMap::new()
249                };
250                buf.clear();
251                Ok(Some(map))
252            } else {
253                todo!();
254            }
255        }
256        Event::End(v) => {
257            assert_eq!(v.name(), b"rows");
258            Ok(None)
259        }
260        _ => todo!(),
261    }
262}
263
264#[cfg(test)]
265mod tests {
266    use quick_xml::{de::Deserializer, DeError};
267
268    use super::*;
269    use quick_xml::Error as XmlError;
270    use std::io::BufReader;
271    use std::io::Cursor;
272
273    #[test]
274    fn test_simple_deserialize() {
275        let st = br#"<row foo="bar"/></rows>"#;
276        let c = BufReader::new(Cursor::new(st));
277        let mut d = Deserializer::from_reader(c);
278        let row = Row::deserialize(&mut d).unwrap();
279        let mut cmp = HashMap::new();
280        let key = String::from("foo");
281        let val = String::from("bar");
282        cmp.insert(key, val);
283        assert_eq!(row.0, cmp);
284
285        if let Err(DeError::Xml(XmlError::EndEventMismatch { expected, found })) =
286            Row::deserialize(&mut d)
287        {
288            assert_eq!(&expected, "");
289            assert_eq!(&found, "rows");
290        }
291    }
292}