From b388a4eb6ecd44654c61aabfc35883ac366c921b Mon Sep 17 00:00:00 2001 From: alexdevteam Date: Sat, 12 Feb 2022 23:27:46 +0100 Subject: [PATCH 1/3] Make path a requirement for parsing --- src/map.rs | 2 +- src/tileset.rs | 91 +++++++++++++++++++++++++------------------------- 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/map.rs b/src/map.rs index 20ae2468..8112d09d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -182,7 +182,7 @@ impl Map { match res.result_type { EmbeddedParseResultType::ExternalReference { tileset_path } => { let file = File::open(&tileset_path).map_err(|err| TiledError::CouldNotOpenFile{path: tileset_path.clone(), err })?; - let tileset = cache.get_or_try_insert_tileset_with(tileset_path.clone(), || Tileset::new_external(file, Some(&tileset_path)))?; + let tileset = cache.get_or_try_insert_tileset_with(tileset_path.clone(), || Tileset::parse_reader(file, &tileset_path))?; tilesets.push(MapTilesetGid{first_gid: res.first_gid, tileset}); } EmbeddedParseResultType::Embedded { tileset } => { diff --git a/src/tileset.rs b/src/tileset.rs index 1efcb5db..51c35fef 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -37,10 +37,6 @@ pub struct Tileset { /// The custom properties of the tileset. pub properties: Properties, - - /// Where this tileset was loaded from. - /// If fully embedded, this will return `None`. - pub source: Option, } pub(crate) enum EmbeddedParseResultType { @@ -62,30 +58,29 @@ struct TilesetProperties { name: String, tile_width: u32, tile_height: u32, - /// The path all non-absolute paths are relative to. - path_relative_to: Option, - source: Option, -} - -impl Tileset { - /// Parse a buffer hopefully containing the contents of a Tiled tileset. - pub fn parse(reader: R) -> Result { - Tileset::new_external(reader, None) - } - - /// Parse a buffer hopefully containing the contents of a Tiled tileset. - pub fn parse_with_path(reader: R, path: impl AsRef) -> Result { - Tileset::new_external(reader, Some(path.as_ref())) - } - - pub fn get_tile(&self, id: u32) -> Option<&Tile> { - self.tiles.get(&id) - } + /// The root all non-absolute paths contained within the tileset are relative to. + root_path: PathBuf, } impl Tileset { - pub(crate) fn new_external(file: R, path: Option<&Path>) -> Result { - let mut tileset_parser = EventReader::new(file); + /// Parses a tileset out of a reader hopefully containing the contents of a Tiled tileset. + /// Uses the `path` parameter as the root for any relative paths found in the tileset. + /// + /// ## Example + /// ``` + /// use std::fs::File; + /// use std::path::PathBuf; + /// use std::io::BufReader; + /// use tiled::Tileset; + /// + /// let path = "assets/tilesheet.tsx"; + /// let reader = BufReader::new(File::open(path).unwrap()); + /// let tileset = Tileset::parse_reader(reader, path).unwrap(); + /// + /// assert_eq!(tileset.image.unwrap().source, PathBuf::from("assets/tilesheet.png")); + /// ``` + pub fn parse_reader(reader: R, path: impl AsRef) -> Result { + let mut tileset_parser = EventReader::new(reader); loop { match tileset_parser .next() @@ -98,7 +93,7 @@ impl Tileset { return Self::parse_external_tileset( &mut tileset_parser.into_iter(), &attributes, - path, + path.as_ref(), ); } } @@ -112,26 +107,31 @@ impl Tileset { } } + /// Gets the tile with the specified ID from the tileset. + pub fn get_tile(&self, id: u32) -> Option<&Tile> { + self.tiles.get(&id) + } +} + +impl Tileset { pub(crate) fn parse_xml_in_map( parser: &mut impl Iterator, attrs: Vec, map_path: &Path, ) -> Result { - let path_relative_to = map_path.parent(); - Tileset::parse_xml_embedded(parser, &attrs, path_relative_to).or_else(|err| { + Tileset::parse_xml_embedded(parser, &attrs, map_path).or_else(|err| { if matches!(err, TiledError::MalformedAttributes(_)) { - Tileset::parse_xml_reference(&attrs, path_relative_to) + Tileset::parse_xml_reference(&attrs, map_path) } else { Err(err) } }) } - /// Returns both the tileset and its first gid in the corresponding map. fn parse_xml_embedded( parser: &mut impl Iterator, attrs: &Vec, - path_relative_to: Option<&Path>, + map_path: &Path, ) -> Result { let ((spacing, margin, columns), (tilecount, first_gid, name, tile_width, tile_height)) = get_attrs!( attrs, @@ -150,18 +150,22 @@ impl Tileset { TiledError::MalformedAttributes("tileset must have a firstgid, name tile width and height with correct types".to_string()) ); + let root_path = map_path + .parent() + .ok_or(TiledError::PathIsNotFile)? + .to_owned(); + Self::finish_parsing_xml( parser, TilesetProperties { spacing, margin, name, - path_relative_to: path_relative_to.map(Path::to_owned), + root_path, columns, tilecount, tile_height, tile_width, - source: None, }, ) .map(|tileset| EmbeddedParseResult { @@ -172,7 +176,7 @@ impl Tileset { fn parse_xml_reference( attrs: &Vec, - path_relative_to: Option<&Path>, + map_path: &Path, ) -> Result { let ((), (first_gid, source)) = get_attrs!( attrs, @@ -184,10 +188,9 @@ impl Tileset { TiledError::MalformedAttributes("Tileset reference must have a firstgid and source with correct types".to_string()) ); - let tileset_path = path_relative_to - .ok_or(TiledError::SourceRequired { - object_to_parse: "Tileset".to_string(), - })? + let tileset_path = map_path + .parent() + .ok_or(TiledError::PathIsNotFile)? .join(source); Ok(EmbeddedParseResult { @@ -199,7 +202,7 @@ impl Tileset { fn parse_external_tileset( parser: &mut impl Iterator, attrs: &Vec, - path: Option<&Path>, + path: &Path, ) -> Result { let ((spacing, margin, columns), (tilecount, name, tile_width, tile_height)) = get_attrs!( attrs, @@ -217,7 +220,7 @@ impl Tileset { TiledError::MalformedAttributes("tileset must have a name, tile width and height with correct types".to_string()) ); - let source_path = path.and_then(|p| p.parent().map(Path::to_owned)); + let root_path = path.parent().ok_or(TiledError::PathIsNotFile)?.to_owned(); Self::finish_parsing_xml( parser, @@ -225,12 +228,11 @@ impl Tileset { spacing, margin, name, - path_relative_to: source_path, + root_path, columns, tilecount, tile_height, tile_width, - source: path.map(Path::to_owned), }, ) } @@ -245,7 +247,7 @@ impl Tileset { parse_tag!(parser, "tileset", { "image" => |attrs| { - image = Some(Image::new(parser, attrs, prop.path_relative_to.as_ref().ok_or(TiledError::SourceRequired{object_to_parse: "Image".to_string()})?)?); + image = Some(Image::new(parser, attrs, &prop.root_path)?); Ok(()) }, "properties" => |_| { @@ -253,7 +255,7 @@ impl Tileset { Ok(()) }, "tile" => |attrs| { - let (id, tile) = Tile::new(parser, attrs, prop.path_relative_to.as_ref().and_then(|p| Some(p.as_path())))?; + let (id, tile) = Tile::new(parser, attrs, Some(&prop.root_path))?; tiles.insert(id, tile); Ok(()) }, @@ -286,7 +288,6 @@ impl Tileset { image, tiles, properties, - source: prop.source, }) } From 1c33b0a1503f90eb1b744ae477d98cd1531fcb6b Mon Sep 17 00:00:00 2001 From: alexdevteam Date: Sat, 12 Feb 2022 23:31:54 +0100 Subject: [PATCH 2/3] Remove `SourceRequired` error --- src/error.rs | 10 ---------- src/tile.rs | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/error.rs b/src/error.rs index b42727d2..3a4e8346 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,11 +13,6 @@ pub enum TiledError { Base64DecodingError(base64::DecodeError), XmlDecodingError(xml::reader::Error), PrematureEnd(String), - /// Tried to parse external data of an object without a file location, - /// e.g. by using Map::parse_reader. - SourceRequired { - object_to_parse: String, - }, /// The path given is invalid because it isn't contained in any folder. PathIsNotFile, CouldNotOpenFile { @@ -49,11 +44,6 @@ impl fmt::Display for TiledError { TiledError::Base64DecodingError(e) => write!(fmt, "{}", e), TiledError::XmlDecodingError(e) => write!(fmt, "{}", e), TiledError::PrematureEnd(e) => write!(fmt, "{}", e), - TiledError::SourceRequired { - ref object_to_parse, - } => { - write!(fmt, "Tried to parse external {} without a file location, e.g. by using Map::parse_reader.", object_to_parse) - } TiledError::PathIsNotFile => { write!( fmt, diff --git a/src/tile.rs b/src/tile.rs index 0493fb50..50413c42 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -27,7 +27,7 @@ impl Tile { pub(crate) fn new( parser: &mut impl Iterator, attrs: Vec, - path_relative_to: Option<&Path>, + path_relative_to: &Path, ) -> Result<(TileId, Tile), TiledError> { let ((tile_type, probability), id) = get_attrs!( attrs, @@ -47,7 +47,7 @@ impl Tile { let mut animation = None; parse_tag!(parser, "tile", { "image" => |attrs| { - image = Some(Image::new(parser, attrs, path_relative_to.ok_or(TiledError::SourceRequired{object_to_parse:"Image".to_owned()})?)?); + image = Some(Image::new(parser, attrs, path_relative_to)?); Ok(()) }, "properties" => |_| { From eff70c5788465e995d416f9935e2d0921abd585c Mon Sep 17 00:00:00 2001 From: alexdevteam Date: Sat, 12 Feb 2022 23:34:32 +0100 Subject: [PATCH 3/3] Fix build --- src/tileset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tileset.rs b/src/tileset.rs index 51c35fef..f4e33caf 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -255,7 +255,7 @@ impl Tileset { Ok(()) }, "tile" => |attrs| { - let (id, tile) = Tile::new(parser, attrs, Some(&prop.root_path))?; + let (id, tile) = Tile::new(parser, attrs, &prop.root_path)?; tiles.insert(id, tile); Ok(()) },