diff --git a/src/entities.rs b/src/entities.rs
new file mode 100644
index 0000000..fc40dc4
--- /dev/null
+++ b/src/entities.rs
@@ -0,0 +1,139 @@
+use std::collections::HashMap;
+
+use anyhow::{anyhow as e, Result};
+use bstr::ByteSlice;
+
+use crate::entity::Entity;
+
+pub fn get_entities(data: &[u8]) -> Result<Vec<Entity>> {
+    let entities = get_entities_maps(data)?
+        .iter()
+        .map(|em| em.into())
+        .collect();
+    Ok(entities)
+}
+
+fn get_entities_maps(data: &[u8]) -> Result<Vec<HashMap<String, String>>> {
+    let ent_string = get_entities_string(data)?;
+
+    let mut entities = Vec::new();
+    let mut current_entity = HashMap::new();
+
+    for line in ent_string.lines() {
+        let line = line.trim();
+
+        if line == "{" {
+            current_entity = HashMap::new();
+        } else if line == "}" {
+            entities.push(current_entity.clone());
+        } else {
+            let parts: Vec<&str> = line.splitn(2, ' ').collect();
+            if parts.len() == 2 {
+                let key = parts[0].trim_matches('"').to_string();
+                let value = parts[1].trim_matches('"').to_string();
+                current_entity.insert(key, value);
+            }
+        }
+    }
+
+    Ok(entities)
+}
+
+fn get_entities_string(data: &[u8]) -> Result<String> {
+    let needle_from: &[u8] = &[123, 10, 34];
+    let Some(index_from) = data.find(needle_from) else {
+        return Err(e!("Entities not found (start needle)"));
+    };
+
+    let needle_to = &[10, 125, 10, 0];
+    let Some(index_to) = data[index_from..]
+        .find(needle_to)
+        .map(|i| index_from + i + 2)
+    else {
+        return Err(e!("Entities not found (end needle)"));
+    };
+
+    Ok(data[index_from..index_to].to_str()?.to_string())
+}
+
+#[cfg(test)]
+mod tests {
+    use std::fs;
+
+    use anyhow::Result;
+    use pretty_assertions::assert_eq;
+
+    use super::*;
+
+    #[test]
+    fn test_get_entities() -> Result<()> {
+        let demo_data = fs::read("test_files/dm3_gpl.bsp")?;
+        let entities = get_entities(&demo_data)?;
+        assert_eq!(entities.len(), 211);
+
+        assert_eq!(
+            entities[0],
+            Entity::WorldSpawn {
+                message: "The Abandoned Base".to_string(),
+                sounds: "6".to_string(),
+                wad: "gfx/base.wad".to_string(),
+                worldtype: "2".to_string(),
+            }
+        );
+
+        assert_eq!(
+            entities[210],
+            Entity::InfoIntermission {
+                mangle: "20 240 0".to_string(),
+                origin: "1840 256 64".to_string(),
+            }
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_get_entities_maps() -> Result<()> {
+        {
+            let demo_data = fs::read("test_files/dm3_gpl.bsp")?;
+            let entities = get_entities_maps(&demo_data)?;
+            assert_eq!(entities.len(), 211);
+            assert_eq!(
+                entities.get(0),
+                Some(&HashMap::from([
+                    ("wad".to_string(), "gfx/base.wad".to_string()),
+                    ("classname".to_string(), "worldspawn".to_string()),
+                    ("worldtype".to_string(), "2".to_string()),
+                    ("sounds".to_string(), "6".to_string()),
+                    ("message".to_string(), "The Abandoned Base".to_string()),
+                ]))
+            );
+            assert_eq!(
+                entities.get(210),
+                Some(&HashMap::from([
+                    ("classname".to_string(), "info_intermission".to_string()),
+                    ("origin".to_string(), "1840 256 64".to_string()),
+                    ("mangle".to_string(), "20 240 0".to_string()),
+                ]))
+            );
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn test_entities_text() -> Result<()> {
+        {
+            let demo_data = fs::read("test_files/dm3_gpl.bsp")?;
+            let result = get_entities_string(&demo_data)?;
+            let expected = fs::read_to_string("test_files/dm3_gpl.entities")?;
+            assert_eq!(result, expected);
+        }
+        {
+            let demo_data = fs::read("test_files/povdmm4.bsp")?;
+            let result = get_entities_string(&demo_data)?;
+            let expected = fs::read_to_string("test_files/povdmm4.entities")?;
+            assert_eq!(result, expected);
+        }
+        Ok(())
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..8337bf1
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod entities;
+pub mod entity;