diff --git a/examples/main.rs b/examples/main.rs
index c4ae445d7c21f05a1d29504181b649ad76678660..c683639689f56f202e4e62dfa59d6489ee98f4dc 100644
--- a/examples/main.rs
+++ b/examples/main.rs
@@ -1,11 +1,13 @@
 use std::fs::File;
-use std::path::Path;
-use tiled::parse;
+use std::path::PathBuf;
+
+use tiled::map::Map;
 
 fn main() {
-    let file = File::open(&Path::new("assets/tiled_base64_zlib.tmx")).unwrap();
+    let path = PathBuf::from("assets/tiled_base64_zlib.tmx");
+    let file = File::open(&path).unwrap();
     println!("Opened file");
-    let map = parse(file).unwrap();
+    let map = Map::parse_reader(file, Some(&path)).unwrap();
     println!("{:?}", map);
-    println!("{:?}", map.get_tileset_by_gid(22));
+    println!("{:?}", map.tileset_by_gid(22));
 }
diff --git a/src/error.rs b/src/error.rs
index 6a502c21c01edaa186ad2a9cca205ee7c963e74f..e3f243c1bf4fab2d73423338d85399337b7017fb 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -2,7 +2,7 @@ use std::fmt;
 
 #[derive(Debug, Copy, Clone)]
 pub enum ParseTileError {
-    ColourError,
+    ColorError,
     OrientationError,
 }
 
diff --git a/src/image.rs b/src/image.rs
index 351cc5bf61ebf59f25543a9ed454780bb4fecc0b..21166f4b0837a6ffc39ef15cc1401b986787a771 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -2,7 +2,7 @@ use std::io::Read;
 
 use xml::{attribute::OwnedAttribute, EventReader};
 
-use crate::{error::TiledError, properties::Colour, util::*};
+use crate::{error::TiledError, properties::Color, util::*};
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub struct Image {
@@ -10,7 +10,7 @@ pub struct Image {
     pub source: String,
     pub width: i32,
     pub height: i32,
-    pub transparent_colour: Option<Colour>,
+    pub transparent_colour: Option<Color>,
 }
 
 impl Image {
diff --git a/src/lib.rs b/src/lib.rs
index 06805e70b8daa4ce9e7102a1f65b57bc57d54e91..2033ef1188ba07f1a3501cfb2d3f1f5213cb5548 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,55 +8,3 @@ pub mod properties;
 pub mod tile;
 pub mod tileset;
 mod util;
-
-use base64;
-
-use error::*;
-use image::*;
-use layers::*;
-use map::*;
-use std::collections::HashMap;
-use std::fmt;
-use std::fs::File;
-use std::io::Read;
-use std::path::{Path, PathBuf};
-use std::str::FromStr;
-use tile::*;
-use tileset::*;
-use util::*;
-use xml::attribute::OwnedAttribute;
-use xml::reader::XmlEvent;
-use xml::reader::{Error as XmlError, EventReader};
-
-// TODO move these
-/// Parse a buffer hopefully containing the contents of a Tiled file and try to
-/// parse it. This augments `parse` with a file location: some engines
-/// (e.g. Amethyst) simply hand over a byte stream (and file location) for parsing,
-/// in which case this function may be required.
-pub fn parse_with_path<R: Read>(reader: R, path: &Path) -> Result<Map, TiledError> {
-    parse_impl(reader, Some(path))
-}
-
-/// Parse a file hopefully containing a Tiled map and try to parse it.  If the
-/// file has an external tileset, the tileset file will be loaded using a path
-/// relative to the map file's path.
-pub fn parse_file(path: &Path) -> Result<Map, TiledError> {
-    let file = File::open(path)
-        .map_err(|_| TiledError::Other(format!("Map file not found: {:?}", path)))?;
-    parse_impl(file, Some(path))
-}
-
-/// Parse a buffer hopefully containing the contents of a Tiled file and try to
-/// parse it.
-pub fn parse<R: Read>(reader: R) -> Result<Map, TiledError> {
-    parse_impl(reader, None)
-}
-
-/// Parse a buffer hopefully containing the contents of a Tiled tileset.
-///
-/// External tilesets do not have a firstgid attribute.  That lives in the
-/// map. You must pass in `first_gid`.  If you do not need to use gids for anything,
-/// passing in 1 will work fine.
-pub fn parse_tileset<R: Read>(reader: R, first_gid: u32) -> Result<Tileset, TiledError> {
-    Tileset::new_external(reader, first_gid)
-}
diff --git a/src/map.rs b/src/map.rs
index f9271fa2dd1234210ab2dcb27662a1b17190750f..7fb0342c1807e94a139f85b4a82283f956bf9333 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -1,38 +1,94 @@
-use std::{collections::HashMap, fmt, io::Read, path::Path, str::FromStr};
+use std::{
+    collections::HashMap,
+    fmt,
+    fs::File,
+    io::Read,
+    path::{Path, PathBuf},
+    str::FromStr,
+};
 
-use xml::{attribute::OwnedAttribute, EventReader};
+use xml::{attribute::OwnedAttribute, reader::XmlEvent, EventReader};
 
 use crate::{
     error::{ParseTileError, TiledError},
     layers::{ImageLayer, Layer},
     objects::ObjectGroup,
-    properties::{parse_properties, Colour, Properties},
+    properties::{parse_properties, Color, Properties},
     tileset::Tileset,
-    util::*,
+    util::{get_attrs, parse_tag},
 };
 
 /// All Tiled files will be parsed into this. Holds all the layers and tilesets
 #[derive(Debug, PartialEq, Clone)]
 pub struct Map {
+    /// The TMX format version this map was saved to.
     pub version: String,
+    /// The orientation of this map.
     pub orientation: Orientation,
-    /// Width of the map, in tiles
+    /// Width of the map, in tiles.
     pub width: u32,
-    /// Height of the map, in tiles
+    /// Height of the map, in tiles.
     pub height: u32,
+    /// Tile width, in pixels.
     pub tile_width: u32,
+    /// Tile height, in pixels.
     pub tile_height: u32,
+    /// The tilesets present in this map.
     pub tilesets: Vec<Tileset>,
+    /// The tile layers present in this map.
     pub layers: Vec<Layer>,
+    /// The image layers present in this map.
     pub image_layers: Vec<ImageLayer>,
+    /// The object groups present in this map.
     pub object_groups: Vec<ObjectGroup>,
+    /// The custom properties of this map.
     pub properties: Properties,
-    pub background_colour: Option<Colour>,
+    /// The background color of this map, if any.
+    pub background_color: Option<Color>,
+    /// Whether this map is infinite or not.
     pub infinite: bool,
+    /// Where this map was loaded from.
+    /// If fully embedded (loaded with path = `None`), this will return `None`.
+    pub source: Option<PathBuf>,
 }
 
 impl Map {
-    pub(crate) fn new<R: Read>(
+    /// Parse a buffer hopefully containing the contents of a Tiled file and try to
+    /// parse it. This augments `parse` with a file location: some engines
+    /// (e.g. Amethyst) simply hand over a byte stream (and file location) for parsing,
+    /// in which case this function may be required.
+    /// The path may be skipped if the map is fully embedded (Doesn't refer to external files).
+    pub fn parse_reader<R: Read>(reader: R, path: Option<&Path>) -> Result<Self, TiledError> {
+        let mut parser = EventReader::new(reader);
+        loop {
+            match parser.next().map_err(TiledError::XmlDecodingError)? {
+                XmlEvent::StartElement {
+                    name, attributes, ..
+                } => {
+                    if name.local_name == "map" {
+                        return Self::parse_xml(&mut parser, attributes, path);
+                    }
+                }
+                XmlEvent::EndDocument => {
+                    return Err(TiledError::PrematureEnd(
+                        "Document ended before map was parsed".to_string(),
+                    ))
+                }
+                _ => {}
+            }
+        }
+    }
+
+    /// Parse a file hopefully containing a Tiled map and try to parse it.  If the
+    /// file has an external tileset, the tileset file will be loaded using a path
+    /// relative to the map file's path.
+    pub fn parse_file(path: &Path) -> Result<Self, TiledError> {
+        let file = File::open(path)
+            .map_err(|_| TiledError::Other(format!("Map file not found: {:?}", path)))?;
+        Self::parse_reader(file, Some(path))
+    }
+
+    fn parse_xml<R: Read>(
         parser: &mut EventReader<R>,
         attrs: Vec<OwnedAttribute>,
         map_path: Option<&Path>,
@@ -62,7 +118,7 @@ impl Map {
         let mut layer_index = 0;
         parse_tag!(parser, "map", {
             "tileset" => |attrs| {
-                tilesets.push(Tileset::new(parser, attrs, map_path)?);
+                tilesets.push(Tileset::parse_xml(parser, attrs, map_path)?);
                 Ok(())
             },
             "layer" => |attrs| {
@@ -97,13 +153,14 @@ impl Map {
             image_layers,
             object_groups,
             properties,
-            background_colour: c,
+            background_color: c,
             infinite: infinite.unwrap_or(false),
+            source: map_path.and_then(|p| Some(p.to_owned())),
         })
     }
 
     /// This function will return the correct Tileset given a GID.
-    pub fn get_tileset_by_gid(&self, gid: u32) -> Option<&Tileset> {
+    pub fn tileset_by_gid(&self, gid: u32) -> Option<&Tileset> {
         let mut maximum_gid: i32 = -1;
         let mut maximum_ts = None;
         for tileset in self.tilesets.iter() {
diff --git a/src/objects.rs b/src/objects.rs
index 3e5edf919dea4938bee8111f7f77ce5597455203..0de2f49b5df6b421b289c4fc3800379ed2aa694b 100644
--- a/src/objects.rs
+++ b/src/objects.rs
@@ -4,7 +4,7 @@ use xml::{attribute::OwnedAttribute, EventReader};
 
 use crate::{
     error::TiledError,
-    properties::{parse_properties, Colour, Properties},
+    properties::{parse_properties, Color, Properties},
     util::{get_attrs, parse_tag},
 };
 
@@ -14,7 +14,7 @@ pub struct ObjectGroup {
     pub opacity: f32,
     pub visible: bool,
     pub objects: Vec<Object>,
-    pub colour: Option<Colour>,
+    pub colour: Option<Color>,
     /**
      * Layer index is not preset for tile collision boxes
      */
diff --git a/src/properties.rs b/src/properties.rs
index 6d9ae472c87c84a822a08ad963bf5a1ef0c4ecbd..9c3dba837693c20443836d75526a339c4923ab01 100644
--- a/src/properties.rs
+++ b/src/properties.rs
@@ -8,31 +8,31 @@ use crate::{
 };
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
-pub struct Colour {
+pub struct Color {
     pub red: u8,
     pub green: u8,
     pub blue: u8,
 }
 
-impl FromStr for Colour {
+impl FromStr for Color {
     type Err = ParseTileError;
 
-    fn from_str(s: &str) -> Result<Colour, ParseTileError> {
+    fn from_str(s: &str) -> Result<Color, ParseTileError> {
         let s = if s.starts_with("#") { &s[1..] } else { s };
         if s.len() != 6 {
-            return Err(ParseTileError::ColourError);
+            return Err(ParseTileError::ColorError);
         }
         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 {
+            return Ok(Color {
                 red: r.unwrap(),
                 green: g.unwrap(),
                 blue: b.unwrap(),
             });
         }
-        Err(ParseTileError::ColourError)
+        Err(ParseTileError::ColorError)
     }
 }
 
diff --git a/src/tileset.rs b/src/tileset.rs
index fe45353523aea6176296d6718ccd682e0688b647..264c78609159edb108e366d6319f583aa3c26cfc 100644
--- a/src/tileset.rs
+++ b/src/tileset.rs
@@ -1,6 +1,17 @@
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::Read;
+use std::path::Path;
+
+use xml::attribute::OwnedAttribute;
+use xml::reader::XmlEvent;
+use xml::EventReader;
+
+use crate::error::TiledError;
+use crate::image::Image;
 use crate::properties::{parse_properties, Properties};
+use crate::tile::Tile;
 use crate::util::*;
-use crate::*; // FIXME
 
 /// A tileset, usually the tilesheet image.
 #[derive(Debug, PartialEq, Clone)]
@@ -21,15 +32,25 @@ pub struct Tileset {
 }
 
 impl Tileset {
-    pub(crate) fn new<R: Read>(
+    /// Parse a buffer hopefully containing the contents of a Tiled tileset.
+    ///
+    /// External tilesets do not have a firstgid attribute.  That lives in the
+    /// map. You must pass in `first_gid`.  If you do not need to use gids for anything,
+    /// passing in 1 will work fine.
+    pub fn parse<R: Read>(reader: R, first_gid: u32) -> Result<Self, TiledError> {
+        Tileset::new_external(reader, first_gid)
+    }
+
+    pub(crate) fn parse_xml<R: Read>(
         parser: &mut EventReader<R>,
         attrs: Vec<OwnedAttribute>,
         map_path: Option<&Path>,
     ) -> Result<Tileset, TiledError> {
-        Tileset::new_internal(parser, &attrs).or_else(|_| Tileset::new_reference(&attrs, map_path))
+        Tileset::parse_xml_embedded(parser, &attrs)
+            .or_else(|_| Tileset::parse_xml_reference(&attrs, map_path))
     }
 
-    fn new_internal<R: Read>(
+    fn parse_xml_embedded<R: Read>(
         parser: &mut EventReader<R>,
         attrs: &Vec<OwnedAttribute>,
     ) -> Result<Tileset, TiledError> {
@@ -81,7 +102,7 @@ impl Tileset {
         })
     }
 
-    fn new_reference(
+    fn parse_xml_reference(
         attrs: &Vec<OwnedAttribute>,
         map_path: Option<&Path>,
     ) -> Result<Tileset, TiledError> {
diff --git a/src/util.rs b/src/util.rs
index 61dcfd1c24bf24cdbebaba82fe17da8e93d048b4..96bc2624f0ceaf73d1fa28a2e3bc17d706013cbd 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -26,9 +26,7 @@ macro_rules! get_attrs {
 }
 
 /// Goes through the children of the tag and will call the correct function for
-/// that child. Closes the tag
-///
-/// Not quite as bad.
+/// that child. Closes the tag.
 macro_rules! parse_tag {
     ($parser:expr, $close_tag:expr, {$($open_tag:expr => $open_method:expr),* $(,)*}) => {
         loop {
@@ -278,24 +276,3 @@ pub(crate) fn convert_to_tile(all: &Vec<u8>, width: u32) -> Vec<Vec<LayerTile>>
     }
     data
 }
-
-pub(crate) fn parse_impl<R: Read>(reader: R, map_path: Option<&Path>) -> Result<Map, TiledError> {
-    let mut parser = EventReader::new(reader);
-    loop {
-        match parser.next().map_err(TiledError::XmlDecodingError)? {
-            XmlEvent::StartElement {
-                name, attributes, ..
-            } => {
-                if name.local_name == "map" {
-                    return Map::new(&mut parser, attributes, map_path);
-                }
-            }
-            XmlEvent::EndDocument => {
-                return Err(TiledError::PrematureEnd(
-                    "Document ended before map was parsed".to_string(),
-                ))
-            }
-            _ => {}
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/lib.rs b/tests/lib.rs
index 92b1a284b368e0d65c51ee4724bf750a00383bc0..5fa1dc1b83e2aa1ab98132f375fcc77cfc42485f 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -1,25 +1,20 @@
 use std::fs::File;
 use std::path::Path;
 use tiled::{
-    error::TiledError, layers::LayerData, map::Map, parse, parse_file, parse_tileset,
-    properties::PropertyValue,
+    error::TiledError, layers::LayerData, map::Map, properties::PropertyValue, tileset::Tileset,
 };
 
-fn read_from_file(p: &Path) -> Result<Map, TiledError> {
+fn parse_map_without_source(p: &Path) -> Result<Map, TiledError> {
     let file = File::open(p).unwrap();
-    return parse(file);
-}
-
-fn read_from_file_with_path(p: &Path) -> Result<Map, TiledError> {
-    return parse_file(p);
+    return Map::parse_reader(file, None);
 }
 
 #[test]
 fn test_gzip_and_zlib_encoded_and_raw_are_the_same() {
-    let z = read_from_file(&Path::new("assets/tiled_base64_zlib.tmx")).unwrap();
-    let g = read_from_file(&Path::new("assets/tiled_base64_gzip.tmx")).unwrap();
-    let r = read_from_file(&Path::new("assets/tiled_base64.tmx")).unwrap();
-    let c = read_from_file(&Path::new("assets/tiled_csv.tmx")).unwrap();
+    let z = parse_map_without_source(&Path::new("assets/tiled_base64_zlib.tmx")).unwrap();
+    let g = parse_map_without_source(&Path::new("assets/tiled_base64_gzip.tmx")).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_base64.tmx")).unwrap();
+    let c = parse_map_without_source(&Path::new("assets/tiled_csv.tmx")).unwrap();
     assert_eq!(z, g);
     assert_eq!(z, r);
     assert_eq!(z, c);
@@ -40,21 +35,34 @@ fn test_gzip_and_zlib_encoded_and_raw_are_the_same() {
 
 #[test]
 fn test_external_tileset() {
-    let r = read_from_file(&Path::new("assets/tiled_base64.tmx")).unwrap();
-    let e = read_from_file_with_path(&Path::new("assets/tiled_base64_external.tmx")).unwrap();
-    assert_eq!(r, e);
+    let r = parse_map_without_source(&Path::new("assets/tiled_base64.tmx")).unwrap();
+    let e = Map::parse_file(&Path::new("assets/tiled_base64_external.tmx")).unwrap();
+    // Compare everything BUT source
+    assert_eq!(r.version, e.version);
+    assert_eq!(r.orientation, e.orientation);
+    assert_eq!(r.width, e.width);
+    assert_eq!(r.height, e.height);
+    assert_eq!(r.tile_width, e.tile_width);
+    assert_eq!(r.tile_height, e.tile_height);
+    assert_eq!(r.tilesets, e.tilesets);
+    assert_eq!(r.layers, e.layers);
+    assert_eq!(r.image_layers, e.image_layers);
+    assert_eq!(r.object_groups, e.object_groups);
+    assert_eq!(r.properties, e.properties);
+    assert_eq!(r.background_color, e.background_color);
+    assert_eq!(r.infinite, e.infinite);
 }
 
 #[test]
 fn test_just_tileset() {
-    let r = read_from_file(&Path::new("assets/tiled_base64.tmx")).unwrap();
-    let t = parse_tileset(File::open(Path::new("assets/tilesheet.tsx")).unwrap(), 1).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_base64.tmx")).unwrap();
+    let t = Tileset::parse(File::open(Path::new("assets/tilesheet.tsx")).unwrap(), 1).unwrap();
     assert_eq!(r.tilesets[0], t);
 }
 
 #[test]
 fn test_infinite_tileset() {
-    let r = read_from_file_with_path(&Path::new("assets/tiled_base64_zlib_infinite.tmx")).unwrap();
+    let r = Map::parse_file(&Path::new("assets/tiled_base64_zlib_infinite.tmx")).unwrap();
 
     if let LayerData::Infinite(chunks) = &r.layers[0].tiles {
         assert_eq!(chunks.len(), 4);
@@ -71,7 +79,7 @@ fn test_infinite_tileset() {
 
 #[test]
 fn test_image_layers() {
-    let r = read_from_file(&Path::new("assets/tiled_image_layers.tmx")).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_image_layers.tmx")).unwrap();
     assert_eq!(r.image_layers.len(), 2);
     {
         let first = &r.image_layers[0];
@@ -97,7 +105,7 @@ fn test_image_layers() {
 
 #[test]
 fn test_tile_property() {
-    let r = read_from_file(&Path::new("assets/tiled_base64.tmx")).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_base64.tmx")).unwrap();
     let prop_value: String = if let Some(&PropertyValue::StringValue(ref v)) =
         r.tilesets[0].tiles[0].properties.get("a tile property")
     {
@@ -110,7 +118,7 @@ fn test_tile_property() {
 
 #[test]
 fn test_object_group_property() {
-    let r = read_from_file(&Path::new("assets/tiled_object_groups.tmx")).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_object_groups.tmx")).unwrap();
     let prop_value: bool = if let Some(&PropertyValue::BoolValue(ref v)) = r.object_groups[0]
         .properties
         .get("an object group property")
@@ -123,7 +131,7 @@ fn test_object_group_property() {
 }
 #[test]
 fn test_tileset_property() {
-    let r = read_from_file(&Path::new("assets/tiled_base64.tmx")).unwrap();
+    let r = parse_map_without_source(&Path::new("assets/tiled_base64.tmx")).unwrap();
     let prop_value: String = if let Some(&PropertyValue::StringValue(ref v)) =
         r.tilesets[0].properties.get("tileset property")
     {
@@ -136,7 +144,7 @@ fn test_tileset_property() {
 
 #[test]
 fn test_flipped_gid() {
-    let r = read_from_file_with_path(&Path::new("assets/tiled_flipped.tmx")).unwrap();
+    let r = Map::parse_file(&Path::new("assets/tiled_flipped.tmx")).unwrap();
 
     if let LayerData::Finite(tiles) = &r.layers[0].tiles {
         let t1 = tiles[0][0];
@@ -165,7 +173,7 @@ fn test_flipped_gid() {
 
 #[test]
 fn test_ldk_export() {
-    let r = read_from_file_with_path(&Path::new("assets/ldk_tiled_export.tmx")).unwrap();
+    let r = Map::parse_file(&Path::new("assets/ldk_tiled_export.tmx")).unwrap();
     if let LayerData::Finite(tiles) = &r.layers[0].tiles {
         assert_eq!(tiles.len(), 8);
         assert_eq!(tiles[0].len(), 8);