gma/
lib.rs

1//! Crate for reading and writing gma files, the file format of garrys mod's addons.
2//! This crate currently does not support opening compressed archives.
3
4mod addon_metadata;
5mod binary;
6mod error;
7mod gma_builder;
8mod gma_reader;
9mod result;
10
11pub use error::Error;
12pub use gma_builder::GMABuilder;
13pub use gma_reader::{FileEntry, GMAFile};
14pub use result::Result;
15use std::convert::TryFrom;
16
17use gma_reader::GMAFileReader;
18
19use std::io::BufReader;
20use std::{
21    io::{BufRead, Cursor, Seek},
22    path::Path,
23};
24
25const IDENT: [u8; 4] = [b'G', b'M', b'A', b'D'];
26const VALID_VERSIONS: [u8; 3] = [1, 2, 3];
27
28#[derive(Debug, Clone, Copy, PartialEq)]
29pub enum AddonType {
30    Gamemode,
31    Map,
32    Weapon,
33    Vehicle,
34    NPC,
35    Entity,
36    Tool,
37    Effects,
38    Model,
39    ServerContent,
40}
41
42impl TryFrom<&str> for AddonType {
43    type Error = Error;
44
45    fn try_from(value: &str) -> Result<Self, Self::Error> {
46        let value_lower = value.to_lowercase();
47        match value_lower.as_str() {
48            "gamemode" => Ok(AddonType::Gamemode),
49            "map" => Ok(AddonType::Map),
50            "weapon" => Ok(AddonType::Weapon),
51            "vehicle" => Ok(AddonType::Vehicle),
52            "npc" => Ok(AddonType::NPC),
53            "entity" => Ok(AddonType::Entity),
54            "tool" => Ok(AddonType::Tool),
55            "effects" => Ok(AddonType::Effects),
56            "model" => Ok(AddonType::Model),
57            "servercontent" => Ok(AddonType::ServerContent),
58            _ => Err(Self::Error::InvalidAddonType(value_lower)),
59        }
60    }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq)]
64pub enum AddonTag {
65    Fun,
66    Roleplay,
67    Scenic,
68    Movie,
69    Realism,
70    Cartoon,
71    Water,
72    Comic,
73    Build,
74}
75
76impl TryFrom<&str> for AddonTag {
77    type Error = Error;
78
79    fn try_from(value: &str) -> Result<Self, Self::Error> {
80        let value_lower = value.to_lowercase();
81        match value_lower.as_str() {
82            "fun" => Ok(AddonTag::Fun),
83            "roleplay" => Ok(AddonTag::Roleplay),
84            "scenic" => Ok(AddonTag::Scenic),
85            "movie" => Ok(AddonTag::Movie),
86            "realism" => Ok(AddonTag::Realism),
87            "cartoon" => Ok(AddonTag::Cartoon),
88            "water" => Ok(AddonTag::Water),
89            "comic" => Ok(AddonTag::Comic),
90            "build" => Ok(AddonTag::Build),
91            _ => Err(Self::Error::InvalidAddonTag(value_lower)),
92        }
93    }
94}
95
96/// Opens a file from disk with the given path and tries to read it as a gma archive
97pub fn open<P>(path: P) -> Result<GMAFile<BufReader<std::fs::File>>>
98where
99    P: AsRef<Path>,
100{
101    let file = std::fs::File::open(path)?;
102    let reader = BufReader::new(file);
103    load(reader)
104}
105
106/// Loads a gma file from a reader
107pub fn load<ReaderType>(r: ReaderType) -> Result<GMAFile<ReaderType>>
108where
109    ReaderType: BufRead + Seek,
110{
111    GMAFileReader::new(r)?.read_gma()
112}
113
114/// Loads a gma file from memory
115pub fn load_from_memory(data: &[u8]) -> Result<GMAFile<Cursor<&[u8]>>> {
116    load(Cursor::new(data))
117}