Newer
Older
use xml::{EventReader, attribute::OwnedAttribute, reader::XmlEvent};
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
use crate::{
error::{ParseTileError, TiledError},
util::{get_attrs, parse_tag},
};
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Colour {
pub red: u8,
pub green: u8,
pub blue: u8,
}
impl FromStr for Colour {
type Err = ParseTileError;
fn from_str(s: &str) -> Result<Colour, ParseTileError> {
let s = if s.starts_with("#") { &s[1..] } else { s };
if s.len() != 6 {
return Err(ParseTileError::ColourError);
}
let r = u8::from_str_radix(&s[0..2], 16);
let g = u8::from_str_radix(&s[2..4], 16);
let b = u8::from_str_radix(&s[4..6], 16);
if r.is_ok() && g.is_ok() && b.is_ok() {
return Ok(Colour {
red: r.unwrap(),
green: g.unwrap(),
blue: b.unwrap(),
});
}
Err(ParseTileError::ColourError)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum PropertyValue {
BoolValue(bool),
FloatValue(f32),
IntValue(i32),
ColorValue(u32),
StringValue(String),
/// Holds the path relative to the map or tileset
FileValue(String),
}
impl PropertyValue {
fn new(property_type: String, value: String) -> Result<PropertyValue, TiledError> {
// Check the property type against the value.
match property_type.as_str() {
"bool" => match value.parse() {
Ok(val) => Ok(PropertyValue::BoolValue(val)),
Err(err) => Err(TiledError::Other(err.to_string())),
},
"float" => match value.parse() {
Ok(val) => Ok(PropertyValue::FloatValue(val)),
Err(err) => Err(TiledError::Other(err.to_string())),
},
"int" => match value.parse() {
Ok(val) => Ok(PropertyValue::IntValue(val)),
Err(err) => Err(TiledError::Other(err.to_string())),
},
"color" if value.len() > 1 => match u32::from_str_radix(&value[1..], 16) {
Ok(color) => Ok(PropertyValue::ColorValue(color)),
Err(_) => Err(TiledError::Other(format!(
"Improperly formatted color property"
))),
},
"string" => Ok(PropertyValue::StringValue(value)),
"file" => Ok(PropertyValue::FileValue(value)),
_ => Err(TiledError::Other(format!(
"Unknown property type \"{}\"",
property_type
))),
}
}
}
pub type Properties = HashMap<String, PropertyValue>;
pub(crate) fn parse_properties<R: Read>(
parser: &mut EventReader<R>,
) -> Result<Properties, TiledError> {
let mut p = HashMap::new();
parse_tag!(parser, "properties", {
"property" => |attrs:Vec<OwnedAttribute>| {
let ((t, v_attr), k) = get_attrs!(
attrs,
optionals: [
("type", property_type, |v| Some(v)),
],
required: [
("name", key, |v| Some(v)),
],
TiledError::MalformedAttributes("property must have a name and a value".to_string())
);
let t = t.unwrap_or("string".into());
let v = match v_attr {
Some(val) => val,
None => {
// if the "value" attribute was missing, might be a multiline string
match parser.next().map_err(TiledError::XmlDecodingError)? {
XmlEvent::Characters(s) => Ok(s),
_ => Err(TiledError::MalformedAttributes(format!("property '{}' is missing a value", k))),
}?
}
};
p.insert(k, PropertyValue::new(t, v)?);