Sign in to follow this  

[.net] Creating a *.package archive

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, so I've been trying to create a *.package archive successfully for a while now. At first, I tried writing directly to a file, but now I've decided writing directly to a memory stream that I can resize at will seems easier. Below is my entire class for reading and writing to and from package files. The reading part need'nt be looked at though, because as far as I can tell, it is fully compatible with all the *.package files I can throw at it.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using Utility;

namespace DBPF.Package
{
    /// <summary>
    /// Represents a *.package as used by The Sims 2. Kept modular to allow
    /// for changes as required by various expansions. Allows for reading,
    /// writing and decompressing *.package files (DBPF).
    /// </summary>
    public class PackageFile
    {
        private string ID;            //(DBPF - the type of dat)
        private string MajorVersion;  //Version Major (1 in TS2/SC4 Dats)
        private string MinorVersion;  //Version Minor (0 in SC4 dats, 1 in most TS2 packages)
        private byte[] Reserved;      //Reserved (Users can store DBPF info data here if they want)
        private string DateCreated;   //Date Created in Hex (Unused in Version 1.1)
        private string DateModified;  //Date Modified in Hex (Unused in Version 1.1)
        private UInt32 IndexMajVer;   //Index Major Version (Always 7 in TS2/SC4 dats)
        private UInt32 NumEntries;    //Number of entries in the index
        private UInt32 FirstEntry;    //Location of first index entry
        private UInt32 IndexSize;     //Size of index
        private UInt32 NumHoles;      //Number of Hole entries in the Hole Record
        private UInt32 HoleLocation;  //Location of the Hole Record
        private UInt32 HoleSize;      //Size of the Hole Record
        private UInt32 IndexLoVer;    //Index Minor Version (Version 1.1+ in TS2 only)
        private byte[] VerReserved;   //Reserved for future use in other versions. 

        private List<IndexEntry> m_IndexTable;
        //Compressed entries in the archive, stored in the archive's *.dir file.
        //Checked against m_IndexTable upon archive extraction, to determine
        //which files are compresed.
        private List<IndexEntry> m_CompressedEntries;

        private FileStream m_MemStream;
        private BinaryReader m_Reader;
        private BinaryWriter m_Writer;
        private ASCIIEncoding m_Encoding;

        //Partially complete index entries generated when creating an NMap for
        //files in a folder that are added to an archive.
        private List<IndexEntry> m_GeneratedIndexEntries;

        private string m_Path;

        /// <summary>
        /// Instantiates a new instance of this class for reading
        /// a *.package archive.
        /// </summary>
        /// <param name="ArchivePath">The full path and name of the archive.</param>
        public PackageFile(string ArchivePath)
        {
            m_IndexTable = new List<IndexEntry>();
            m_CompressedEntries = new List<IndexEntry>();

            m_MemStream = File.OpenRead(ArchivePath);
            m_Reader = new BinaryReader(m_MemStream);
            m_Encoding = new ASCIIEncoding();
        }

        /// <summary>
        /// Instantiates a new instance of this class for
        /// creating a *.package archive from a directory.
        /// </summary>
        /// <param name="DirPath">The full path and name of the directory.</param>
        /// <param name="Compress">Set to true if you wish to compress archive.</param>
        public PackageFile(string DirPath, bool Compress)
        {
            m_MemStream = File.Create(DirPath + "\\" + Path.GetFileNameWithoutExtension(DirPath) + ".package");
            m_Encoding = new ASCIIEncoding();
            m_GeneratedIndexEntries = new List<IndexEntry>();

            m_Path = DirPath;

            FindExtensionsInDir();
            CreatePackage();
        }

        /// <summary>
        /// Finds all the extensions in the directory given to the
        /// constructor of this class, and creates NMaps for them.
        /// </summary>
        private void FindExtensionsInDir()
        {
            string[] Files = Directory.GetFiles(m_Path);
            List<string> Extensions = new List<string>();

            foreach (string TmpFile in Files)
            {
                string TmpExtension = Path.GetExtension(TmpFile);
                Extensions.Add(TmpExtension);
            }

            string[] ExtensionsArray = Extensions.ToArray();

            for (int i = 0; i < Extensions.Count; i++)
            {
                if (!ExtensionsArray[i].Equals(".package"))
                {
                    if (i != 0)
                    {
                        //Current extension in the array didn't equal the last one,
                        //so we know we can create a NameMap for it.
                        if (!ExtensionsArray[i].Equals(ExtensionsArray[i - 1]))
                        {
                            NameMap NMap = new NameMap(NameMap.DetermineTypeID(ExtensionsArray[i]), m_Path);
                            m_GeneratedIndexEntries.AddRange(NMap.CreateNMap());
                        }
                    }
                    else if (i == 0)
                    {
                        NameMap NMap = new NameMap(NameMap.DetermineTypeID(ExtensionsArray[i]), m_Path);
                        m_GeneratedIndexEntries.AddRange(NMap.CreateNMap());
                    }
                }
            }
        }

        private void CreatePackage()
        {
            MemoryStream PackageStream = new MemoryStream();
            BinaryWriter PackageWriter = new BinaryWriter(PackageStream);

            PackageStream = WriteFilesToPackage(PackageWriter, PackageStream);
            PackageStream.Seek(0, SeekOrigin.Begin);

            PackageStream = WriteIndexTable(PackageWriter, PackageStream);
            PackageStream.Seek(0, SeekOrigin.Begin);

            PackageStream = WritePackageHeader(PackageWriter, PackageStream);
            PackageStream.Seek(0, SeekOrigin.Begin);
            
            m_Reader = new BinaryReader(PackageStream);
            m_Writer = new BinaryWriter(m_MemStream);

            m_Writer.Write(m_Reader.ReadBytes((int)PackageStream.Length));
            m_Writer.Flush();

            PackageWriter.Close();
            m_Writer.Close();
            m_Reader.Close();
        }

        #region Archive writing functions

        private MemoryStream WritePackageHeader(BinaryWriter Writer, MemoryStream MemStream)
        {
            MemStream.SetLength(MemStream.Length + 96);

            //Identifier (DBPF - the type of dat).
            Writer.Write(m_Encoding.GetBytes("DBPF"));
            //Version Major (1 in TS2/SC4 Dats). 
            Writer.Write((uint)1);
            //Version Minor (0 in SC4 dats, 1 in most TS2 packages).
            Writer.Write((uint)1);
            //Reserved (Users can store DBPF info data here if they want).
            Writer.Write(new byte[12]);
            //Date Created in Hex (Unused in Version 1.1).
            Writer.Write((uint)0);
            //Date Modified in Hex (Unused in Version 1.1).
            Writer.Write((uint)0);
            //Index Major Version (Always 7 in TS2/SC4 dats).
            Writer.Write((uint)7);
            //Number of entries in the index.
            Writer.Write((uint)m_GeneratedIndexEntries.Count);
            //Location of first index entry.
            Writer.Write((uint)96);
            //Size of index.
            Writer.Write(IndexSize);
            //Number of Hole entries in the Hole Record.
            Writer.Write((uint)0);
            //Location of the Hole Record. 
            Writer.Write((uint)0);
            //Size of the Hole Record.
            Writer.Write((uint)0);
            //Index Minor Version (Version 1.1+ in TS2 only).
            //01 = 0 
            //02 = 1
            Writer.Write((uint)01);
            //Reserved for future use in other versions.
            Writer.Write(new byte[32]);

            return MemStream;
        }

        private MemoryStream WriteIndexTable(BinaryWriter Writer, MemoryStream MemStream)
        {
            uint TmpIndexSize = 0;

            foreach (IndexEntry TmpEntry in m_GeneratedIndexEntries)
            {
                TmpIndexSize += 5 * 4; //20 bytes
                MemStream.SetLength(MemStream.Length + TmpIndexSize);

                Writer.Write(TmpEntry.TypeID);
                Writer.Write(TmpEntry.GroupID);
                Writer.Write(TmpEntry.InstanceID);
                Writer.Write(TmpEntry.Location);
                Writer.Write(TmpEntry.Size);
                Writer.Flush();
            }

            IndexSize = TmpIndexSize;

            return MemStream;
        }

        private MemoryStream WriteFilesToPackage(BinaryWriter Writer, MemoryStream MemStream)
        {
            FileStream FStream;
            BinaryReader FileReader;

            foreach (IndexEntry TmpEntry in m_GeneratedIndexEntries)
            {
                FStream = File.OpenRead(TmpEntry.Name);
                FileReader = new BinaryReader(FStream);

                TmpEntry.Location = (uint)MemStream.Position;
                TmpEntry.Size = (uint)FStream.Length;
                Writer.Write(FileReader.ReadBytes((int)FStream.Length));
                Writer.Flush();

                FileReader.Close();
            } 

            return MemStream;
        }

        #endregion

        #region Archive reading functions

        /// <summary>
        /// Reads the header of a *.package (DBPF) archive.
        /// </summary>
        /// <returns>True if header was read, false if archive
        ///          wasn't a DBPF archive.</returns>
        private bool ReadHeader()
        {
            ID = m_Encoding.GetString(m_Reader.ReadBytes(4));

            if (!ID.Equals("DBPF"))
            {
                MessageBox.Show("Couldn't read package ID!");
                return false;
            }

            MajorVersion = HexEncoding.ToString(m_Reader.ReadBytes(4));
            MinorVersion = HexEncoding.ToString(m_Reader.ReadBytes(4));

            Reserved = m_Reader.ReadBytes(12);

            DateCreated = HexEncoding.ToString(m_Reader.ReadBytes(4));
            DateModified = HexEncoding.ToString(m_Reader.ReadBytes(4));

            IndexMajVer = m_Reader.ReadUInt32();

            NumEntries = m_Reader.ReadUInt32();
            FirstEntry = m_Reader.ReadUInt32();
            IndexSize = m_Reader.ReadUInt32();

            NumHoles = m_Reader.ReadUInt32();
            HoleLocation = m_Reader.ReadUInt32();
            HoleSize = m_Reader.ReadUInt32();
            IndexLoVer = m_Reader.ReadUInt32() - 1;

            VerReserved = m_Reader.ReadBytes(32);

            return true;
        }

        /// <summary>
        /// Reads the index table of a *.package (DBPF) archive.
        /// </summary>
        private void ReadIndex()
        {
            m_MemStream.Seek(FirstEntry, SeekOrigin.Begin);

            for (int i = 0; i < NumEntries; i++)
            {
                try
                {
                    IndexEntry TmpEntry = new IndexEntry();

                    TmpEntry.TypeID = m_Reader.ReadUInt32();
                    TmpEntry.GroupID = m_Reader.ReadUInt32();
                    TmpEntry.InstanceID = m_Reader.ReadUInt32();
                    
                    //Check the archive's version to determine whether or not to read
                    //a second instance ID.

                    if ((IndexMajVer == 7) && (IndexLoVer == 1))
                        TmpEntry.InstanceID2 = m_Reader.ReadUInt32();

                    TmpEntry.Location = m_Reader.ReadUInt32();
                    TmpEntry.Size = m_Reader.ReadUInt32();

                    //Check for *.dir file, which is a directory of all
                    //compressed files in an archive.
                    if ((InternalPackageFormats)TmpEntry.TypeID == InternalPackageFormats.Directory)
                    {
                        long CurrentStreamPos = m_MemStream.Position;
                        m_MemStream.Seek(TmpEntry.Location, SeekOrigin.Begin);
                        
                        //Dump filedata into the entry's databuffer.
                        TmpEntry.Data = new MemoryStream(m_Reader.ReadBytes((int)TmpEntry.Size));
                        TmpEntry.DataReader = new BinaryReader(TmpEntry.Data);

                        //Loop through the filedata, reading all the dir entries
                        //of compressed files, and add them to m_CompressedEntries.
                        for (int j = 0; j <= TmpEntry.Size; j++)
                        {
                            IndexEntry CompressedEntry = new IndexEntry();

                            CompressedEntry.TypeID = TmpEntry.DataReader.ReadUInt32();
                            CompressedEntry.GroupID = TmpEntry.DataReader.ReadUInt32();
                            CompressedEntry.InstanceID = TmpEntry.DataReader.ReadUInt32();
                            CompressedEntry.UnpackedHexSize = HexEncoding.ToString(TmpEntry.DataReader.ReadBytes(4));

                            //A dir entry in the *.dir file/record takes 16 bytes.
                            j += 12 + CompressedEntry.UnpackedHexSize.Length;

                            m_CompressedEntries.Add(CompressedEntry);
                        }

                        //Seek back to the position in the index table where we left off.
                        m_MemStream.Seek(CurrentStreamPos, SeekOrigin.Begin);
                        
                        TmpEntry.Data.Close();
                        TmpEntry.DataReader.Close();
                    }

                    m_IndexTable.Add(TmpEntry);
                }
                catch (Exception)
                {
                    return;
                }
            }
        }

        public void ExtractArchive(string Path)
        {
            foreach (IndexEntry CompressedEntry in m_CompressedEntries)
            {
                foreach (IndexEntry TmpEntry in m_IndexTable)
                {
                    if (CompressedEntry.InstanceID == TmpEntry.InstanceID)
                        TmpEntry.Compressed = true;
                }
            }

            int CurrentFilename = 0;
            string CurrentExtension = string.Empty;
            
            BinaryWriter Writer;
            FileStream Stream;

            if (!Directory.Exists(Path))
                Directory.CreateDirectory(Path);

            foreach (IndexEntry TmpEntry in m_IndexTable)
            {
                m_MemStream.Seek(TmpEntry.Location, SeekOrigin.Begin);

                //Dump filedata into the entry's databuffer.
                TmpEntry.Data = new MemoryStream(m_Reader.ReadBytes((int)TmpEntry.Size));
                TmpEntry.DataReader = new BinaryReader(TmpEntry.Data);

                if (TmpEntry.Compressed)
                {
                    TmpEntry.ReadCompressedHeader();

                    byte[] buf = Uncompress(TmpEntry.Data.ToArray(), TmpEntry.UnpackedSize, 9);
                    TmpEntry.Data = new MemoryStream(buf);
                    buf = null;
                }

                CurrentFilename++;
                CurrentExtension = DetermineFileExtension((InternalPackageFormats)TmpEntry.TypeID);

                Stream = File.Open(Path + "\\" + CurrentFilename + CurrentExtension, FileMode.OpenOrCreate);
                Writer = new BinaryWriter(Stream);

                Writer.Write(TmpEntry.Data.ToArray());

                TmpEntry.Data.Close();
                TmpEntry.DataReader.Close();

                Stream.Close();
                Writer.Close();
            }
        }

        #endregion

        public bool LoadArchive()
        {
            if (!ReadHeader())
                return false;

            ReadIndex();

            return true;
        }

        #region Helper Functions

        /// <summary>
        /// Uncompresses the File Data passed
        /// </summary>
        /// <param name="data">Relevant File Data</param>
        /// <param name="targetSize">Size of the uncompressed Data</param>
        /// <param name="offset">File offset, where we should start to decompress from</param>
        /// <returns>The uncompressed FileData</returns>
        public static Byte[] Uncompress(Byte[] data, uint targetSize, int offset)
        {
            Byte[] uncdata = null;
            int index = offset;

            try
            {
                uncdata = new Byte[targetSize];
            }
            catch (Exception)
            {
                uncdata = new Byte[0];
            }

            int uncindex = 0;
            int plaincount = 0;
            int copycount = 0;
            int copyoffset = 0;
            Byte cc = 0;
            Byte cc1 = 0;
            Byte cc2 = 0;
            Byte cc3 = 0;
            int source;

            try
            {
                while ((index < data.Length) && (data[index] < 0xfc))
                {
                    cc = data[index++];

                    if ((cc & 0x80) == 0)
                    {
                        cc1 = data[index++];
                        plaincount = (cc & 0x03);
                        copycount = ((cc & 0x1C) >> 2) + 3;
                        copyoffset = ((cc & 0x60) << 3) + cc1 + 1;
                    }
                    else if ((cc & 0x40) == 0)
                    {
                        cc1 = data[index++];
                        cc2 = data[index++];
                        plaincount = (cc1 & 0xC0) >> 6;
                        copycount = (cc & 0x3F) + 4;
                        copyoffset = ((cc1 & 0x3F) << 8) + cc2 + 1;
                    }
                    else if ((cc & 0x20) == 0)
                    {
                        cc1 = data[index++];
                        cc2 = data[index++];
                        cc3 = data[index++];
                        plaincount = (cc & 0x03);
                        copycount = ((cc & 0x0C) << 6) + cc3 + 5;
                        copyoffset = ((cc & 0x10) << 12) + (cc1 << 8) + cc2 + 1;
                    }
                    else
                    {
                        plaincount = (cc - 0xDF) << 2;
                        copycount = 0;
                        copyoffset = 0;
                    }

                    for (int i = 0; i < plaincount; i++) uncdata[uncindex++] = data[index++];

                    source = uncindex - copyoffset;
                    for (int i = 0; i < copycount; i++) uncdata[uncindex++] = uncdata[source++];
                }//while
            } //try
            catch (Exception ex)
            {
                //Helper.ExceptionMessage("", ex);
                throw ex;
            }

            if (index < data.Length)
            {
                plaincount = (data[index++] & 0x03);
                for (int i = 0; i < plaincount; i++)
                {
                    if (uncindex >= uncdata.Length) break;
                    uncdata[uncindex++] = data[index++];
                }
            }
            return uncdata;
        }

        private string DetermineFileExtension(InternalPackageFormats TypeID)
        {
            switch (TypeID)
            {
                case InternalPackageFormats.UIData:
                    return ".ui";
                case InternalPackageFormats.WallGraph:
                    return ".wgra";
                case InternalPackageFormats.LotDescription:
                    return ".desc";
                case InternalPackageFormats.BinaryIndex:
                    return ".binx";
                case InternalPackageFormats.JPG:
                    return ".jpg";
                case InternalPackageFormats.NameReference:
                    return ".nref";
                case InternalPackageFormats.BusinessInfo:
                    return ".bnfo";
                case InternalPackageFormats.TextureImage:
                    return ".txtr";
                case InternalPackageFormats.XA:
                    return ".xa";
                case InternalPackageFormats.ThreeDArray:
                    return ".3dary";
                case InternalPackageFormats.TwoDArray:
                    return ".2dary";
                case InternalPackageFormats.TextureOverlay:
                    return ".xtol";
                case InternalPackageFormats.Popups:
                    return ".pops";
                case InternalPackageFormats.SimScores:
                    return ".scor";
                case InternalPackageFormats.ThreeDID:
                    return ".3didr";
                case InternalPackageFormats.BehaviourConstant:
                    return "bcon";
                case InternalPackageFormats.BehaviourFunction:
                    return "bhav";
                case InternalPackageFormats.CatalogString:
                    return ".cats";
                case InternalPackageFormats.CatalogDescription:
                    return ".ctss";
                case InternalPackageFormats.TextLists:
                    return ".str#";
                case InternalPackageFormats.PieMenuStrings:
                    return ".tta";
                case InternalPackageFormats.FaceProperties:
                    return ".face";
                case InternalPackageFormats.FamilyInformation:
                    return ".fami";
                case InternalPackageFormats.FamilyUnknown:
                    return "famh";
                case InternalPackageFormats.Function:
                    return ".fcns";
                case InternalPackageFormats.AudioReference:
                    return "fwav";
                case InternalPackageFormats.GlobalData:
                    return ".glob";
                case InternalPackageFormats.HouseDescriptor:
                    return ".hous";
                case InternalPackageFormats.TexturedMaterial:
                    return ".txmt";
                case InternalPackageFormats.WorldDatabase:
                    return ".wrld";
                case InternalPackageFormats.SkinToneXML:
                    return ".xstn";
                case InternalPackageFormats.CinematicScene:
                    return ".cine";
                case InternalPackageFormats.Memory:
                    return ".ngbh";
                case InternalPackageFormats.NameMap:
                    return ".nmap";
                case InternalPackageFormats.ObjectData:
                    return ".objd";
                case InternalPackageFormats.ObjectFunctions:
                    return ".objf";
                case InternalPackageFormats.ObjectMaterial:
                    return ".objm";
                case InternalPackageFormats.ImageColorPalette:
                    return ".palt";
                case InternalPackageFormats.PERS:
                    return ".pers";
                case InternalPackageFormats.Slot:
                    return ".slot";
                case InternalPackageFormats.TTAT:
                    return ".ttat";
                case InternalPackageFormats.TRPR:
                    return ".trpr";
                case InternalPackageFormats.TRCN:
                    return ".trcn";
                case InternalPackageFormats.Object:
                    return ".mobjt";
                case InternalPackageFormats.HitList:
                    return ".hls";
                case InternalPackageFormats.GeometricNode:
                    return ".gmnd";
                case InternalPackageFormats.LightMap:
                    return ".lightmap";
                case InternalPackageFormats.WallLayer:
                    return ".wll";
                case InternalPackageFormats.FamilyTies:
                    return ".famt";
                case InternalPackageFormats.PMAP:
                    return ".pmap";
                case InternalPackageFormats.SimDescription:
                    return ".pdat";
                case InternalPackageFormats.FencePostLayer:
                    return ".fpl";
                case InternalPackageFormats.HoodTerrain:
                    return ".nhtr";
                case InternalPackageFormats.NID:
                    return ".nid";
                case InternalPackageFormats.AgedCPF:
                    return ".cpf";
                case InternalPackageFormats.Anim:
                    return ".anim";
                case InternalPackageFormats.SMAP:
                    return ".smap";
                case InternalPackageFormats.BMP:
                    return ".bmp";
                case InternalPackageFormats.Vertext:
                    return ".vertext";
                case InternalPackageFormats.FacialStructure:
                    return ".lxnr";
                case InternalPackageFormats.MaterialShader:
                    return ".matshad";
                case InternalPackageFormats.WantsFears:
                    return ".wfr";
                case InternalPackageFormats.ContentRegistry:
                    return ".creg";
                case InternalPackageFormats.CIGE:
                    return ".cige";
                case InternalPackageFormats.ResourceNode:
                    return ".cres";
                case InternalPackageFormats.PropertySet:
                    return ".cpf";
                case InternalPackageFormats.VersionInfo:
                    return ".ver";
                case InternalPackageFormats.HoodView:
                    return ".nhvw";
                case InternalPackageFormats.LargeImage:
                    return ".lifo";
                case InternalPackageFormats.OBJT:
                    return ".objt";
                case InternalPackageFormats.Shape:
                    return ".shpe";
                case InternalPackageFormats.EffectsScript:
                    return ".fx";
                case InternalPackageFormats.GeometricData:
                    return ".gmdc";
                case InternalPackageFormats.LargeJPG:
                    return ".jfif";
                case InternalPackageFormats.BHAVTree:
                    return ".tree";
                default:
                    return ".xyz";
            }
        }

        #endregion

        /// <summary>
        /// Returns an array representing the IndexTable of the loaded archive.
        /// The index table contains entries which in turn contains information
        /// about each file in the archive that they represent, such as location
        /// and size of actual filedata, as well as a type ID representing the 
        /// file's extension.
        /// </summary>
        public IndexEntry[] IndexTable
        {
            get { return m_IndexTable.ToArray(); }
        }
    }
}



The problem, if it isn't obvious yet, is that I am as of yet incapable of creating *.package files that can be extracted with my *.package reading code (and, thus, by other *.package reading tools as well). A thing I've noticed is that when I try to extract a *.package archive created with my *.package writing methods, the files seems to grow in size incrementally as they are extracted/created, which seems to suggest that there is something wrong with the way I am writing my Index Table. If needed, here's the specification I'm using for this code: *.package specification Any suggestions? Thanks in advance! Edit - Whoops, here's the class for creating NMaps;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace DBPF.Package
{
    /// <summary>
    /// Encapsulates methods for creating, and returning a handle to, a
    /// new NameMap file that can be put in a new *.package file along
    /// with the files referenced in the new NameMap file.
    /// </summary>
    class NameMap
    {
        private string m_Filename;            //Filename of this file (unimportant, as these files don't map their own names).
        private string m_Path;                //Path of the created file.
        private InternalPackageFormats m_TypeID; //TypeID of the filetype that this file maps.
        private uint m_NumItems;              //Number of files with the filetype that corresponds to this file.

        List<IndexEntry> m_Files;            //List of files that are contained in this NMap.

        public NameMap(InternalPackageFormats TypeID, string Path)
        {
            m_TypeID = TypeID;
            m_Path = Path;
            m_Filename = DetermineFileExtension(m_TypeID).Replace(".", "");
            m_Files = new List<IndexEntry>();
        }

        public List<IndexEntry> CreateNMap()
        {
            string[] Files = Directory.GetFiles(m_Path);

            FileStream NMap = File.Create(m_Path + "\\" + m_Filename + ".nmap");
            BinaryWriter Writer = new BinaryWriter(NMap);

            Random Rnd = new Random();

            m_NumItems = (uint)Files.Length;

            Writer.Write(m_NumItems);

            uint InstanceID = 0;

            foreach (string TmpName in Files)
            {
                if (DetermineFileExtension(m_TypeID).Equals(Path.GetExtension(TmpName)))
                {
                    IndexEntry TmpEntry = new IndexEntry();

                    TmpEntry.Name = TmpName;
                    TmpEntry.InstanceID = InstanceID++;
                    TmpEntry.TypeID = (uint)m_TypeID;

                    //Is it neccessary to 'fill out' GroupID?
                    Writer.Write((uint)0x0);
                    Writer.Write(TmpEntry.InstanceID);
                    Writer.Write((uint)TmpEntry.Name.Length);
                    Writer.Write(Encoding.ASCII.GetBytes(Path.GetFileNameWithoutExtension(TmpEntry.Name)));

                    m_Files.Add(TmpEntry);
                }
            }

            IndexEntry NMapEntry = new IndexEntry();
            NMapEntry.Name = m_Path + "\\" + m_Filename + ".nmap";
            NMapEntry.InstanceID = InstanceID++;
            NMapEntry.TypeID = (uint)InternalPackageFormats.NameMap;

            m_Files.Add(NMapEntry);

            NMap.Close();
            Writer.Close();

            return m_Files;
        }

        #region Helper Functions

        /// <summary>
        /// Determines a filetype based upon a TypeID.
        /// </summary>
        /// <param name="TypeID">A TypeID in the InternalPackageFormats enum.</param>
        /// <returns>A string containing the filetype.</returns>
        private string DetermineFileExtension(InternalPackageFormats TypeID)
        {
            switch (TypeID)
            {
                case InternalPackageFormats.UIData:
                    return ".ui";
                case InternalPackageFormats.WallGraph:
                    return ".wgra";
                case InternalPackageFormats.LotDescription:
                    return ".desc";
                case InternalPackageFormats.BinaryIndex:
                    return ".binx";
                case InternalPackageFormats.JPG:
                    return ".jpg";
                case InternalPackageFormats.NameReference:
                    return ".nref";
                case InternalPackageFormats.BusinessInfo:
                    return ".bnfo";
                case InternalPackageFormats.TextureImage:
                    return ".txtr";
                case InternalPackageFormats.XA:
                    return ".xa";
                case InternalPackageFormats.ThreeDArray:
                    return ".3dary";
                case InternalPackageFormats.TwoDArray:
                    return ".2dary";
                case InternalPackageFormats.TextureOverlay:
                    return ".xtol";
                case InternalPackageFormats.Popups:
                    return ".pops";
                case InternalPackageFormats.SimScores:
                    return ".scor";
                case InternalPackageFormats.ThreeDID:
                    return ".3didr";
                case InternalPackageFormats.BehaviourConstant:
                    return ".bcon";
                case InternalPackageFormats.BehaviourFunction:
                    return ".bhav";
                case InternalPackageFormats.CatalogString:
                    return ".cats";
                case InternalPackageFormats.CatalogDescription:
                    return ".ctss";
                case InternalPackageFormats.TextLists:
                    return ".str#";
                case InternalPackageFormats.PieMenuStrings:
                    return ".tta";
                case InternalPackageFormats.FaceProperties:
                    return ".face";
                case InternalPackageFormats.FamilyInformation:
                    return ".fami";
                case InternalPackageFormats.FamilyUnknown:
                    return ".famh";
                case InternalPackageFormats.Function:
                    return ".fcns";
                case InternalPackageFormats.AudioReference:
                    return ".fwav";
                case InternalPackageFormats.GlobalData:
                    return ".glob";
                case InternalPackageFormats.HouseDescriptor:
                    return ".hous";
                case InternalPackageFormats.TexturedMaterial:
                    return ".txmt";
                case InternalPackageFormats.WorldDatabase:
                    return ".wrld";
                case InternalPackageFormats.SkinToneXML:
                    return ".xstn";
                case InternalPackageFormats.CinematicScene:
                    return ".cine";
                case InternalPackageFormats.Memory:
                    return ".ngbh";
                case InternalPackageFormats.NameMap:
                    return ".nmap";
                case InternalPackageFormats.ObjectData:
                    return ".objd";
                case InternalPackageFormats.ObjectFunctions:
                    return ".objf";
                case InternalPackageFormats.ObjectMaterial:
                    return ".objm";
                case InternalPackageFormats.ImageColorPalette:
                    return ".palt";
                case InternalPackageFormats.PERS:
                    return ".pers";
                case InternalPackageFormats.Slot:
                    return ".slot";
                case InternalPackageFormats.TTAT:
                    return ".ttat";
                case InternalPackageFormats.TRPR:
                    return ".trpr";
                case InternalPackageFormats.TRCN:
                    return ".trcn";
                case InternalPackageFormats.Object:
                    return ".mobjt";
                case InternalPackageFormats.HitList:
                    return ".hls";
                case InternalPackageFormats.GeometricNode:
                    return ".gmnd";
                case InternalPackageFormats.LightMap:
                    return ".lightmap";
                case InternalPackageFormats.WallLayer:
                    return ".wll";
                case InternalPackageFormats.FamilyTies:
                    return ".famt";
                case InternalPackageFormats.PMAP:
                    return ".pmap";
                case InternalPackageFormats.SimDescription:
                    return ".pdat";
                case InternalPackageFormats.FencePostLayer:
                    return ".fpl";
                case InternalPackageFormats.HoodTerrain:
                    return ".nhtr";
                case InternalPackageFormats.NID:
                    return ".nid";
                case InternalPackageFormats.AgedCPF:
                    return ".cpf";
                case InternalPackageFormats.Anim:
                    return ".anim";
                case InternalPackageFormats.SMAP:
                    return ".smap";
                case InternalPackageFormats.BMP:
                    return ".bmp";
                case InternalPackageFormats.Vertext:
                    return ".vertext";
                case InternalPackageFormats.FacialStructure:
                    return ".lxnr";
                case InternalPackageFormats.MaterialShader:
                    return ".matshad";
                case InternalPackageFormats.WantsFears:
                    return ".wfr";
                case InternalPackageFormats.ContentRegistry:
                    return ".creg";
                case InternalPackageFormats.CIGE:
                    return ".cige";
                case InternalPackageFormats.ResourceNode:
                    return ".cres";
                case InternalPackageFormats.PropertySet:
                    return ".cpf";
                case InternalPackageFormats.VersionInfo:
                    return ".ver";
                case InternalPackageFormats.HoodView:
                    return ".nhvw";
                case InternalPackageFormats.LargeImage:
                    return ".lifo";
                case InternalPackageFormats.OBJT:
                    return ".objt";
                case InternalPackageFormats.Shape:
                    return ".shpe";
                case InternalPackageFormats.EffectsScript:
                    return ".fx";
                case InternalPackageFormats.GeometricData:
                    return ".gmdc";
                case InternalPackageFormats.LargeJPG:
                    return ".jfif";
                case InternalPackageFormats.BHAVTree:
                    return ".tree";
                case InternalPackageFormats.DirectXMesh:
                    return ".x";
                default:
                    return "xyz";
            }
        }

        /// <summary>
        /// Determines a TypeID based upon a file extension.
        /// </summary>
        /// <param name="Extension">The extension of a file.</param>
        /// <returns>A TypeID in the InternalPackageFormats enum.</returns>
        public static InternalPackageFormats DetermineTypeID(string Extension)
        {
            switch (Extension)
            {
                case ".cpf":
                    return InternalPackageFormats.AgedCPF;
                case ".x":
                    return InternalPackageFormats.DirectXMesh;
                default:
                    return InternalPackageFormats.UnkownFiletype;
            }
        }

        #endregion
    }
}

Just in case, here's the specs: NMap Specification

Share this post


Link to post
Share on other sites
I can't be arsed to read all of that code at the moment, but typically if something is growing that shouldn't, that typically means something you think is being deleted really isn't (which is common when working with streams, at least with me). If I were you I'd simply trace down to the line/function that causes the size to grow when it should, that would, of course, point you in the right direction.

Share this post


Link to post
Share on other sites

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this