diff options
Diffstat (limited to 'WAD.cs')
-rw-r--r-- | WAD.cs | 365 |
1 files changed, 365 insertions, 0 deletions
@@ -0,0 +1,365 @@ +// Noddybox.DOOM - DOOM WAD Wrapper +// Copyright (C) 2004 Ian Cowburn +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +using System; +using System.IO; +using System.Collections; +using System.Text; + +namespace Noddybox.DOOM +{ + /// <summary> + /// Defines a WAD File + /// </summary> + public class WAD : IEnumerable, IEnumerator + { + // ==================================== + // PUBLIC + // ==================================== + + /// <summary> + /// Describes the type of WAD + /// </summary> + public enum EWadType + { + /// <summary> + /// An Interal WAD (eg. DOOM 2) + /// </summary> + IWAD, + + /// <summary> + /// A Patch WAD (eg. a user-defined level) + /// </summary> + PWAD + }; + + /// <summary> + /// Construct a new, empty WAD file + /// </summary> + public WAD() + { + m_type=EWadType.PWAD; + m_entry=new ArrayList(); + m_ascii=new ASCIIEncoding(); + } + + /// <summary> + /// Load a WAD file from disk + /// </summary> + /// <param name="path">The WAD file</param> + /// <exception cref="System.IO.IOException"> + /// I/O errors + /// </exception> + public WAD(string path) + { + m_path=path; + m_entry=new ArrayList(); + m_ascii=new ASCIIEncoding(); + Load(); + } + + /// <summary> + /// Get/set the path of the WAD file on disk + /// </summary> + public string Path + { + get {return m_path;} + set {m_path=value;} + } + + /// <summary> + /// Get the type of WAD file + /// </summary> + public EWadType WadType + { + get {return m_type;} + } + + /// <summary> + /// Adds a new lump to the WAD + /// </summary> + /// <param name="e">The lump</param> + public void AddEntry(WADEntry e) + { + m_entry.Add(e); + } + + /// <summary> + /// Removes a lump from the WAD + /// </summary> + /// <param name="e">The lump</param> + public void RemoveEntry(WADEntry e) + { + m_entry.Remove(e); + } + + /// <summary> + /// Find a lump + /// </summary> + /// <param name="name">The name to find</param> + /// <returns>The first lump that matches the name, or null for no match</returns> + public WADEntry FindEntry(string name) + { + foreach (WADEntry e in m_entry) + { + if (e.Name==name) + { + return e; + } + } + + return null; + } + + /// <summary> + /// Load a WAD file + /// </summary> + /// <exception cref="System.IO.IOException"> + /// I/O errors + /// </exception> + public void Load() + { + if (m_path==null) + { + throw new DoomException("Tried to load a WAD without a path"); + } + + FileStream fs=File.OpenRead(m_path); + + string id=ReadString(fs,4); + + if (id=="IWAD") + { + m_type=EWadType.IWAD; + } + else if (id=="PWAD") + { + m_type=EWadType.PWAD; + } + else + { + fs.Close(); + throw new DoomException("Not a WAD File - " + m_path); + } + + m_entry.Clear(); + + int num=ReadLong(fs); + + if (num>0) + { + fs.Position=ReadLong(fs); + + for(int f=0;f<num;f++) + { + int off=ReadLong(fs); + int len=ReadLong(fs); + string name=ReadString(fs,8); + + long cur=fs.Position; + + byte[] data=new byte[len]; + + fs.Position=off; + fs.Read(data,0,len); + fs.Position=cur; + + m_entry.Add(new WADEntry(name,data)); + } + } + + fs.Close(); + } + + /// <summary> + /// Saves the WAD file + /// </summary> + /// <exception cref="Noddybox.DOOM.DoomException"> + /// Tried to save an IWAD file + /// </exception> + /// <exception cref="System.IO.IOException"> + /// I/O errors + /// </exception> + public void Save() + { + if (m_path==null) + { + throw new DoomException("Tried to save a WAD without a path"); + } + + if (m_type==EWadType.IWAD) + { + throw new DoomException("Tried to save an IWAD"); + } + + FileStream fs=File.Create(m_path); + + int len=0; + + foreach (WADEntry e in this) + { + len+=e.Length; + } + + WriteString(fs,"PWAD",4); + WriteLong(fs,m_entry.Count); + + int offset=12; + + WriteLong(fs,len+offset); + + foreach (WADEntry e in m_entry) + { + fs.Write(e.Data,0,e.Length); + } + + foreach (WADEntry e in m_entry) + { + WriteLong(fs,offset); + WriteLong(fs,e.Length); + WriteString(fs,e.Name,8); + offset+=e.Length; + } + + fs.Close(); + } + + /// <summary> + /// Returns the number of lumps in the WAD + /// </summary> + public int Count + { + get {return m_entry.Count;} + } + + /// <summary> + /// Index into the lumps + /// </summary> + public WADEntry this[int index] + { + get {return (WADEntry)m_entry[index];} + } + + /// <summary> + /// Gets an enumerator + /// </summary> + /// <returns>The enumerator</returns> + public IEnumerator GetEnumerator() + { + Reset(); + return this; + } + + /// <summary> + /// Get the current object from the enumerator + /// </summary> + public object Current + { + get + { + if (m_iter_index==-1) + { + throw new InvalidOperationException(); + } + + return m_entry[m_iter_index]; + } + } + + /// <summary> + /// Reset the enumerator to the start of the collection. + /// </summary> + public void Reset() + { + m_iter_index=-1; + } + + /// <summary> + /// Move the enumerator to the next item. + /// </summary> + /// <returns>True if there are more objects to enumerate over</returns> + public bool MoveNext() + { + m_iter_index++; + + if (m_iter_index>=m_entry.Count) + { + m_iter_index=-1; + } + + return m_iter_index!=-1; + } + + // ==================================== + // PRIVATE + // ==================================== + private string m_path; + private EWadType m_type; + private ArrayList m_entry; + private ASCIIEncoding m_ascii; + + private int m_iter_index; + + private int ReadLong(FileStream fs) + { + int l=0; + + for(int f=0;f<4;f++) + { + int b=fs.ReadByte(); + l|=b<<(f*8); + } + + return l; + } + + private string ReadString(FileStream fs, int len) + { + byte[] data=new byte[len]; + + fs.Read(data,0,len); + + return m_ascii.GetString(data,0,len); + } + + private void WriteLong(FileStream fs, int l) + { + for(int f=0;f<4;f++) + { + fs.WriteByte((byte)(l&0xff)); + l=l>>8; + } + } + + private void WriteString(FileStream fs, string s, int len) + { + byte[] data=m_ascii.GetBytes(s); + + for(int f=0;f<len;f++) + { + if (f<data.Length) + { + fs.WriteByte(data[f]); + } + else + { + fs.WriteByte(0); + } + } + } + } +} |