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