Esempio n. 1
0
        private FileEntry GetFileEntry_(
            EndianBinaryReader er,
            RarcHeader header,
            RarcNode node,
            int i)
        {
            er.Position = 0x20 +
                          header.fileEntriesOffset +
                          node.firstFileEntryOffset +
                          i * 20;

            var fileEntry = new FileEntry();

            fileEntry.id             = er.ReadUInt16();
            fileEntry.unknown        = er.ReadUInt16();
            fileEntry.unknown2       = er.ReadUInt16();
            fileEntry.filenameOffset = er.ReadUInt16();

            fileEntry.dataOffset = er.ReadUInt32();

            fileEntry.dataSize = er.ReadUInt32();
            fileEntry.zero     = er.ReadUInt32();

            return(fileEntry);
        }
Esempio n. 2
0
        private RarcNode GetNode_(EndianBinaryReader er, RarcHeader h, int i)
        {
            var node = new RarcNode();

            node.type = er.ReadString(Encoding.UTF8, 4);

            var fileNameOffset       = er.ReadUInt32();
            var expectedFileNameHash = er.ReadUInt16();

            node.numFileEntries       = er.ReadUInt16();
            node.firstFileEntryOffset = er.ReadUInt32();

            var position = er.Position;

            {
                er.Position   = 0x20 + h.stringTableOffset + fileNameOffset;
                node.fileName = er.ReadStringNT(Encoding.UTF8);

                var actualFileNameHash = 0;
                foreach (var c in node.fileName)
                {
                    actualFileNameHash *= 3;
                    actualFileNameHash += (byte)c;
                }
                Asserts.Equal(expectedFileNameHash,
                              actualFileNameHash,
                              "Node did not have the correct hash!");
            }
            { }
            er.Position = position;

            return(node);
        }
Esempio n. 3
0
        private bool ReadFile_(IFileHierarchyFile rarcFile)
        {
            using var er = new EndianBinaryReader(rarcFile.Impl.OpenRead());

            var header = new RarcHeader();

            header.type = er.ReadString(Encoding.ASCII, 4);

            if (header.type != "RARC")
            {
                return(false);
            }

            header.size            = er.ReadUInt32();
            header.unknown         = er.ReadUInt32();
            header.dataStartOffset = er.ReadUInt32();
            er.ReadUInt32s(header.unknown2);

            header.numNodes          = er.ReadUInt32();
            header.firstNodeOffset   = er.ReadUInt32();
            header.numDirectories    = er.ReadUInt32();
            header.fileEntriesOffset = er.ReadUInt32();
            header.stringTableLength = er.ReadUInt32();
            header.stringTableOffset = er.ReadUInt32();
            er.ReadUInt32s(header.unknown5);


            var cwd = Directory.GetCurrentDirectory();

            var directoryPath = rarcFile.FullName + "_dir";

            {
                var nodes = new RarcNode[header.numNodes];
                for (var i = 0; i < header.numNodes; ++i)
                {
                    nodes[i] = this.GetNode_(er, header, i);
                }

                ;

                foreach (var node in nodes)
                {
                    Directory.SetCurrentDirectory(directoryPath);
                    this.DumpNode_(er, node, header);
                }
            }

            Directory.SetCurrentDirectory(cwd);

            return(true);
        }
Esempio n. 4
0
        FileEntry getFileEntry(int i, RarcHeader h, BinaryReader f)
        {
            f.BaseStream.Seek(h.fileEntriesOffset + (i * sizeoffe) + 0x20, 0);
            FileEntry ret;

            ret.id = toWORD(f.ReadUInt16());
            f.ReadUInt16(); // unknown
            f.ReadUInt16(); // unknown2
            ret.filenameOffset = toWORD(f.ReadUInt16());
            ret.dataOffset     = toDWORD(f.ReadUInt32());
            ret.dataSize       = toDWORD(f.ReadUInt32());
            ret.zero           = toDWORD(f.ReadUInt32());

            return(ret);
        }
Esempio n. 5
0
        void dumpNode(Node n, RarcHeader h, BinaryReader f, String path)
        {
            string nodeName = getString((int)(n.filenameOffset + h.stringTableOffset + 0x20), f); // get the name of this node.

            toOutput("Unpacking: " + nodeName + "...");
            path += "\\" + nodeName;

            DirectoryInfo dir = Directory.CreateDirectory(path);

            dir.Create();

            for (int i = 0; i < n.numFileEntries; i++)
            {
                // Get the current FileEntry
                FileEntry curr = getFileEntry((int)(n.firstFileEntryOffset + i), h, f);
                if (curr.id == 0xFFFF)                                          // subdirectory
                {
                    if (curr.filenameOffset != 0 && curr.filenameOffset != 2)   // don't go to "." and ".."
                    {
                        dumpNode(getNode((int)curr.dataOffset, f), h, f, path); // dump the node associated with curr if it's a directory.
                    }
                }
                else // file
                {
                    // If it's a file, the read the data from the offset and write it into a file with the name at the proper offset.
                    string currName = getString((int)(curr.filenameOffset + h.stringTableOffset + 0x20), f);

                    Stream nf = new FileStream(path + "\\" + currName, FileMode.Create, FileAccess.Write); // open new file stream.
                    f.BaseStream.Seek(curr.dataOffset + h.dataStartOffset, 0);                             // seek to start of file data.

                    // Read and write the data in 1024 byte chunks.
                    UInt32 read = 0;
                    byte[] buff = new byte[1024];
                    while (read < curr.dataSize)
                    {
                        int rAmount = Math.Min(1024, (int)(curr.dataSize - read));
                        f.Read(buff, 0, rAmount);
                        nf.Write(buff, 0, rAmount);
                        read += (UInt32)rAmount;
                    }
                    nf.Close(); // make sure to close our stream!
                }
            }
        }
Esempio n. 6
0
 private void DumpNode_(EndianBinaryReader er, RarcNode node, RarcHeader h)
 {
     /*
      * string nodeName = getString(0x20 + n.filenameOffset + h.stringTableOffset, f);
      * _mkdir(nodeName.c_str());
      * _chdir(nodeName.c_str());
      *
      * for (int i = 0; i < n.numFileEntries; ++i) {
      *  RarcDump.FileEntry curr = getFileEntry(n.firstFileEntryOffset + i, h, f);
      *
      *  if (curr.id == 0xFFFF) //subdirectory
      *  {
      *    if (curr.filenameOffset != 0 &&
      *        curr.filenameOffset != 2) //don't go to "." and ".."
      *      dumpNode(getNode(curr.dataOffset, f), h, f);
      *  } else //file
      *  {
      *    string currName =
      *        getString(curr.filenameOffset + h.stringTableOffset + 0x20, f);
      *    cout << nodeName << "/" << currName << endl;
      *    FILE* dest = fopen(currName.c_str(), "wb");
      *
      *    u32 read = 0;
      *    u8 buff[1024];
      *    fseek(f, curr.dataOffset + h.dataStartOffset + 0x20, SEEK_SET);
      *    while (read < curr.dataSize) {
      *      int r = fread(buff, 1, min(1024, curr.dataSize - read), f);
      *      fwrite(buff, 1, r, dest);
      *      read += r;
      *    }
      *    fclose(dest);
      *  }
      * }
      *
      * _chdir("..");       */
 }
Esempio n. 7
0
        public void Rarc(string[] args, string saveDesitination)
        {
            //This is a hack to enable debugging
            //args = new string[1];
            //args[0] = @"H:\Games\NGC\fsa root\GC4Sword\Boss\boss010.arc_dir\boss010";
            //Once complete the above two lines can recieve the chop


            stringTable = CreateStringTable();//Setup the string table

            //Get all directories and sub-ones in an array and create an appropriately sized Node array
            string[] allDirectories = Directory.GetDirectories(args[0], "*", SearchOption.AllDirectories);
            nodes = new Node[allDirectories.Length + 1]; //Add 1 for the ROOT node

            numNodesDone      = 0;
            numFilesWithData  = 0;
            lengthOfDataTable = 0;

            //Fill out the ROOT node
            nodes[0].type = "ROOT";

            nodes[0].filenameOffset = (uint)stringTable.Length;
            String rootDirName = new FileInfo(args[0]).Name;

            stringTable = stringTable + rootDirName + (char)0x00;

            nodes[0].foldernameHash = Hash(rootDirName);

            string[] files = Directory.GetFileSystemEntries(args[0]);
            nodes[0].numFileEntries = (ushort)(files.Length + 2);

            nodes[0].firstFileEntryOffset = 0;

            numNodesDone++; //One node is complete


            //Get the total number of subdirectories and files
            string[] allFiles          = Directory.GetFiles(args[0], "*", SearchOption.AllDirectories);
            int      numOfFilesAndDirs = allFiles.Length + allDirectories.Length;

            //Now set up an array of FileEntrys(Taking into account the "." and ".." file entries for each folder
            fileEntries = new FileEntry[numOfFilesAndDirs + (allDirectories.Length * 2) + 2];

            filesData          = new string[allFiles.Length]; //Setup an array to store all the file data paths in
            totalNumFilesAdded = 0;                           //How many file entries have been done


            //CURRENTLY ONLY GOES TWO FOLDERS DEEP
            //Create FileEntry for each file in current folder
            string[] folders = ProcessFilesAndFolders(args);
            //For each folder
            for (int i = 0; i < folders.Length; i++)
            {
                args[0] = folders[i];
                CreateNode(args);
                string[] folders2 = ProcessFilesAndFolders(args);

                //Do that again for any files/folders in this folder
                for (int i2 = 0; i2 < folders2.Length; i2++)
                {
                    args[0] = folders2[i2];
                    CreateNode(args);
                    ProcessFilesAndFolders(args);
                }
            }

            //Fill out the filename & data offsets for the folder entries with the offset from the appropriate Node
            for (int n = 0; n < totalNumFilesAdded; n++)
            {
                if (fileEntries[n].filenameOffset == 0xFFFE)
                {
                    uint nodeNum = 0;
                    foreach (Node node in nodes)
                    {
                        if (node.foldernameHash == fileEntries[n].filenameHash)
                        {
                            fileEntries[n].filenameOffset = (ushort)node.filenameOffset;
                            fileEntries[n].dataOffset     = nodeNum;
                        }
                        nodeNum++;
                    }
                }
            }

            //Make the data table a mutiple of 16
            int numOfPaddingBytes = 0;

            while ((lengthOfDataTable % 16) != 0)
            {
                lengthOfDataTable++;
                numOfPaddingBytes++;
            }

            //Fill out Header information
            RarcHeader header = new RarcHeader();

            header.type              = "RARC";
            header.numFiles1         = (uint)totalNumFilesAdded;
            header.numFiles2         = (ushort)totalNumFilesAdded;
            header.sizeOfDataTable1  = lengthOfDataTable;
            header.sizeOfDataTable2  = lengthOfDataTable;
            header.unknown1          = 0x20;
            header.unknown6          = 0x20;
            header.unknown8          = 0x100;
            header.fileEntriesOffset = (numNodesDone * 16) + 0x20;
            if ((header.fileEntriesOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
            {
                header.fileEntriesOffset += 16;
            }

            header.numNodes = numNodesDone;

            int x = 0;

            while (0 != ((totalNumFilesAdded * 20) + x) % 16)
            {
                x++;
            }
            header.stringTableOffset = header.fileEntriesOffset + (uint)((totalNumFilesAdded * 20) + x);
            if ((header.stringTableOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
            {
                header.stringTableOffset += 16;
            }

            while (0 != (stringTable.Length) % 16)//Pad out the string table so the data table starts at a 0based address
            {
                stringTable = stringTable + (char)0x00;
            }
            header.dataStartOffset = (uint)(header.stringTableOffset + stringTable.Length);
            if ((header.dataStartOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
            {
                header.dataStartOffset += 16;
            }

            header.sizeOfStringTable = (uint)stringTable.Length;
            header.size = lengthOfDataTable + header.dataStartOffset + 0x20;



            //Let's write it out
            FileStream   filestreamWriter = new FileStream(saveDesitination, FileMode.Create);
            BinaryWriter binWriter        = new BinaryWriter(filestreamWriter);

            //First the Header is written
            binWriter.Write(header.type[0]);
            binWriter.Write(header.type[1]);
            binWriter.Write(header.type[2]);
            binWriter.Write(header.type[3]);
            byte[] buffer = BitConverter.GetBytes(header.size);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.dataStartOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfDataTable1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.sizeOfDataTable2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown4);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown5);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numNodes);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown6);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.numFiles1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.fileEntriesOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);


            buffer = BitConverter.GetBytes(header.sizeOfStringTable);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.stringTableOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.numFiles2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown8);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);
            buffer = BitConverter.GetBytes(header.unknown9);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            //Write each of the nodes
            foreach (Node currentNode in nodes)
            {
                binWriter.Write(currentNode.type[0]);
                if (currentNode.type.Length > 1)       //Incase the dirname is only 1 char long
                {
                    binWriter.Write(currentNode.type[1]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }
                if (currentNode.type.Length > 2)       //Incase the dirname is only 2 char long
                {
                    binWriter.Write(currentNode.type[2]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }
                if (currentNode.type.Length == 4)       //Incase the dirname is only 3 char long
                {
                    binWriter.Write(currentNode.type[3]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }

                buffer = BitConverter.GetBytes(currentNode.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.foldernameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.numFileEntries);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.firstFileEntryOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the file entries at their correct offset
            while (filestreamWriter.Position != (header.fileEntriesOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write all the file entries
            foreach (FileEntry entry in fileEntries)
            {
                buffer = BitConverter.GetBytes(entry.id);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.filenameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.unknown2);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.dataOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.dataSize);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(entry.zero);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the string table at its correct offset
            while (filestreamWriter.Position != (header.stringTableOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write string table
            Encoding enc = Encoding.UTF8;

            binWriter.Write(enc.GetBytes(stringTable));

            //Pad out the file to get the data table at its correct offset
            while (filestreamWriter.Position != (header.dataStartOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write files data
            foreach (string file in filesData)
            {
                buffer = File.ReadAllBytes(file);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                while ((filestreamWriter.Position % 32) != 0)//Pad out the data so the next file begins on a 0-based multiple of 32
                {
                    filestreamWriter.WriteByte(0x00);
                }
            }
            for (int pad = 0; pad < numOfPaddingBytes; pad++)//Write the bytes neccessary to make the entire file divisble by 32
            {
                filestreamWriter.WriteByte(0x00);
            }

            binWriter.Close();
            filestreamWriter.Close();

            Console.WriteLine("Packed and good to go!");
        }
        public static void CompressRARC(string FullPath, RARC.FileNode Root)
        {
            Console.WriteLine("\n>> Compressing " + Root.NodeName + " to " + FullPath);
            string newFile = Root.NodeName;

            stringTable = CreateStringTable();            //Setup the string table

            int directoriesCount = countRARCDirs(Root);

            nodes = new Node[directoriesCount + 1];             //Add 1 for the ROOT node

            numNodesDone      = 0;
            numFilesWithData  = 0;
            lengthOfDataTable = 0;

            //Fill out the ROOT node
            nodes[0].type = "ROOT";

            nodes[0].filenameOffset = (uint)stringTable.Length;
            String rootDirName = newFile;

            stringTable = stringTable + rootDirName + (char)0x00;

            nodes[0].foldernameHash = Hash(rootDirName);

            nodes[0].numFileEntries = (ushort)(Root.Files.Count + Root.ChildNodes.Count + 2);

            nodes[0].firstFileEntryOffset = 0;

            numNodesDone++;             //One node is complete


            //Get the total number of subdirectories and files
            //string[] allFiles = Directory.GetFiles(args[0], "*", SearchOption.AllDirectories);
            //int numOfFilesAndDirs = allFiles.Length + directoriesCount;
            int filesCount        = countRARCFiles(Root);
            int numOfFilesAndDirs = filesCount + directoriesCount;

            //Now set up an array of FileEntrys(Taking into account the "." and ".." file entries for each folder
            fileEntries = new FileEntry[numOfFilesAndDirs + (directoriesCount * 2) + 2];
            Console.WriteLine("# fileEntries " + (numOfFilesAndDirs + (directoriesCount * 2) + 2));

            filesData          = new byte[filesCount][]; //Setup an array to store all the file data paths in
            totalNumFilesAdded = 0;                      //How many file entries have been done


            CreateEntries(Root);


            //Fill out the filename & data offsets for the folder entries with the offset from the appropriate Node
            for (int n = 0; n < totalNumFilesAdded; n++)
            {
                if (fileEntries[n].filenameOffset == 0xFFFE)
                {
                    uint nodeNum = 0;
                    foreach (Node node in nodes)
                    {
                        if (node.foldernameHash == fileEntries[n].filenameHash)
                        {
                            fileEntries[n].filenameOffset = (ushort)node.filenameOffset;
                            fileEntries[n].dataOffset     = nodeNum;
                        }
                        nodeNum++;
                    }
                }
            }

            //Make the data table a mutiple of 16
            int numOfPaddingBytes = 0;

            while ((lengthOfDataTable % 16) != 0)
            {
                lengthOfDataTable++;
                numOfPaddingBytes++;
            }

            //Fill out Header information
            RarcHeader header = new RarcHeader();

            header.type             = "RARC";
            header.numFiles1        = (uint)totalNumFilesAdded;
            header.numFiles2        = (ushort)totalNumFilesAdded;
            header.sizeOfDataTable1 = lengthOfDataTable;
            header.sizeOfDataTable2 = lengthOfDataTable;
            header.unknown1         = 0x20;
            header.unknown6         = 0x20;
            header.unknown8         = 0x100;

            header.fileEntriesOffset = (numNodesDone * 16) + 0x20;
            if ((header.fileEntriesOffset % 32) != 0)            //Check if it's a multiple of 32 and make it one if it's not
            {
                header.fileEntriesOffset += 16;
            }

            Console.WriteLine("fileEntriesOffset is: " + header.fileEntriesOffset);
            Console.WriteLine("totalNumFilesAdded: " + (totalNumFilesAdded + 1));
            header.numNodes = numNodesDone;

            int numFileEntries = (numOfFilesAndDirs + (directoriesCount * 2) + 2);

            int x = 0;

            while (0 != (((numFileEntries) * 20) + x) % 16)
            {
                x++;
            }

            header.stringTableOffset = header.fileEntriesOffset + (uint)((numFileEntries * 20) + x);
            if ((header.stringTableOffset % 32) != 0)            //Check if it's a multiple of 32 and make it one if it's not
            {
                header.stringTableOffset += 16;
            }

            Console.WriteLine("stringTableOffset is: " + header.stringTableOffset);

            while (0 != (stringTable.Length) % 16)            //Pad out the string table so the data table starts at a 0based address
            {
                stringTable = stringTable + (char)0x00;
            }

            header.dataStartOffset = (uint)(header.stringTableOffset + stringTable.Length);
            if ((header.dataStartOffset % 32) != 0)            //Check if it's a multiple of 32 and make it one if it's not
            {
                header.dataStartOffset += 16;
            }

            Console.WriteLine("dataStartOffset is: " + header.dataStartOffset);


            header.sizeOfStringTable = (uint)stringTable.Length;
            header.size = lengthOfDataTable + header.dataStartOffset + 0x20;

            //Let's write it out

            // Uncomment while testing
            //FullPath += ".new.arc";

            FileStream   filestreamWriter = new FileStream(FullPath, FileMode.Create);
            BinaryWriter binWriter        = new BinaryWriter(filestreamWriter);

            Console.WriteLine("Writing to file: " + FullPath);
            Console.WriteLine("Writing header...");
            //First the Header is written
            binWriter.Write(header.type[0]);
            binWriter.Write(header.type[1]);
            binWriter.Write(header.type[2]);
            binWriter.Write(header.type[3]);

            byte[] buffer = BitConverter.GetBytes(header.size);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.dataStartOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfDataTable1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfDataTable2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown4);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown5);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numNodes);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown6);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numFiles1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.fileEntriesOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);


            buffer = BitConverter.GetBytes(header.sizeOfStringTable);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.stringTableOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numFiles2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown8);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown9);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            Console.WriteLine("Writing nodes...");
            //Write each of the nodes
            foreach (Node currentNode in nodes)
            {
                Console.WriteLine("Writing " + currentNode.type);
                binWriter.Write(currentNode.type[0]);
                if (currentNode.type.Length > 1)                       //Incase the dirname is only 1 char long
                {
                    binWriter.Write(currentNode.type[1]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }
                if (currentNode.type.Length > 2)                       //Incase the dirname is only 2 char long
                {
                    binWriter.Write(currentNode.type[2]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }
                if (currentNode.type.Length == 4)                       //Incase the dirname is only 3 char long
                {
                    binWriter.Write(currentNode.type[3]);
                }
                else
                {
                    filestreamWriter.WriteByte(0x20);
                }

                buffer = BitConverter.GetBytes(currentNode.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.foldernameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.numFileEntries);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.firstFileEntryOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the file entries at their correct offset
            while (filestreamWriter.Position < (header.fileEntriesOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write all the file entries
            foreach (FileEntry entry in fileEntries)
            {
                Console.WriteLine(String.Format("Writing fileEntry {0:X6}", entry.filenameOffset));

                buffer = BitConverter.GetBytes(entry.id);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.filenameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.unknown2);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.dataOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.dataSize);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.zero);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the string table at its correct offset

            while (filestreamWriter.Position < (header.stringTableOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write string table
            Encoding enc = Encoding.UTF8;

            binWriter.Write(enc.GetBytes(stringTable));

            //Pad out the file to get the data table at its correct offset
            while (filestreamWriter.Position < (header.dataStartOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write files data
            foreach (byte[] file in filesData)
            {
                Console.WriteLine("Dumping file data...");
                buffer = file;
                filestreamWriter.Write(buffer, 0, buffer.Length);
                while ((filestreamWriter.Position % 32) != 0)                //Pad out the data so the next file begins on a 0-based multiple of 32
                {
                    filestreamWriter.WriteByte(0x00);
                }
            }
            for (int pad = 0; pad < numOfPaddingBytes; pad++)            //Write the bytes neccessary to make the entire file divisble by 32
            {
                filestreamWriter.WriteByte(0x00);
            }

            binWriter.Close();
            filestreamWriter.Close();

            Console.WriteLine("Packed and good to go!");
        }
Esempio n. 9
0
        public static void CompressRARC(string FullPath, RARC.FileNode Root)
        {
            Console.WriteLine("\n>> Compressing " + Root.NodeName + " to " + FullPath);
            string newFile = Root.NodeName;

            stringTable = CreateStringTable();//Setup the string table

            int directoriesCount = countRARCDirs(Root);
            nodes = new Node[directoriesCount + 1]; //Add 1 for the ROOT node

            numNodesDone = 0;
            numFilesWithData = 0;
            lengthOfDataTable = 0;

            //Fill out the ROOT node
            nodes[0].type = "ROOT";

            nodes[0].filenameOffset = (uint)stringTable.Length;
            String rootDirName = newFile;
            stringTable = stringTable + rootDirName + (char)0x00;

            nodes[0].foldernameHash = Hash(rootDirName);

            int filesCount = countRARCFiles (Root);
            nodes[0].numFileEntries = (ushort)(filesCount + 2);

            nodes[0].firstFileEntryOffset = 0;

            numNodesDone++; //One node is complete

            //Get the total number of subdirectories and files
            //string[] allFiles = Directory.GetFiles(args[0], "*", SearchOption.AllDirectories);
            //int numOfFilesAndDirs = allFiles.Length + directoriesCount;
            int numOfFilesAndDirs = filesCount + directoriesCount;

            //Now set up an array of FileEntrys(Taking into account the "." and ".." file entries for each folder
            fileEntries = new FileEntry[numOfFilesAndDirs + (directoriesCount * 2) + 2];
            Console.WriteLine("# fileEntries " + (numOfFilesAndDirs + (directoriesCount * 2) + 2));

            filesData = new byte[filesCount][]; //Setup an array to store all the file data paths in
            totalNumFilesAdded = 0; //How many file entries have been done

            CreateEntries(Root);

            //Fill out the filename & data offsets for the folder entries with the offset from the appropriate Node
            for (int n = 0; n < totalNumFilesAdded; n++)
            {
                if (fileEntries[n].filenameOffset == 0xFFFE)
                {
                    uint nodeNum = 0;
                    foreach (Node node in nodes)
                    {
                        if (node.foldernameHash == fileEntries[n].filenameHash)
                        {
                            fileEntries[n].filenameOffset = (ushort)node.filenameOffset;
                            fileEntries[n].dataOffset = nodeNum;
                        }
                        nodeNum++;
                    }
                }
            }

            //Make the data table a mutiple of 16
            int numOfPaddingBytes = 0;
            while ((lengthOfDataTable % 16) != 0)
            {
                lengthOfDataTable++;
                numOfPaddingBytes++;
            }

            //Fill out Header information
            RarcHeader header = new RarcHeader();
            header.type = "RARC";
            header.numFiles1 = (uint)totalNumFilesAdded;
            header.numFiles2 = (ushort)totalNumFilesAdded;
            header.sizeOfDataTable1 = lengthOfDataTable;
            header.sizeOfDataTable2 = lengthOfDataTable;
            header.unknown1 = 0x20;
            header.unknown6 = 0x20;
            header.unknown8 = 0x100;

            header.fileEntriesOffset = (numNodesDone * 16) + 0x20;
            if ((header.fileEntriesOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
                header.fileEntriesOffset += 16;

            Console.WriteLine("fileEntriesOffset is: " + header.fileEntriesOffset);
            Console.WriteLine("totalNumFilesAdded: " + (totalNumFilesAdded+1));
            header.numNodes = numNodesDone;

            int numFileEntries = (numOfFilesAndDirs + (directoriesCount * 2) + 2);

            int x = 0;
            while (0 != (((numFileEntries) * 20) + x) % 16)
                x++;

            header.stringTableOffset = header.fileEntriesOffset + (uint)((numFileEntries * 20) + x);
            if ((header.stringTableOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
                header.stringTableOffset += 16;

            Console.WriteLine("stringTableOffset is: " + header.stringTableOffset);

            while (0 != (stringTable.Length) % 16)//Pad out the string table so the data table starts at a 0based address
                stringTable = stringTable + (char)0x00;

            header.dataStartOffset = (uint)(header.stringTableOffset + stringTable.Length);
            if ((header.dataStartOffset % 32) != 0)//Check if it's a multiple of 32 and make it one if it's not
                header.dataStartOffset += 16;

            Console.WriteLine("dataStartOffset is: " + header.dataStartOffset);

            header.sizeOfStringTable = (uint)stringTable.Length;
            header.size = lengthOfDataTable + header.dataStartOffset + 0x20;

            //Let's write it out

            // Uncomment while testing
            //FullPath += ".new.arc";

            FileStream filestreamWriter = new FileStream(FullPath, FileMode.Create);
            BinaryWriter binWriter = new BinaryWriter(filestreamWriter);

            Console.WriteLine("Writing to file: " + FullPath);
            Console.WriteLine("Writing header...");
            //First the Header is written
            binWriter.Write(header.type[0]);
            binWriter.Write(header.type[1]);
            binWriter.Write(header.type[2]);
            binWriter.Write(header.type[3]);

            byte[] buffer = BitConverter.GetBytes(header.size);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.dataStartOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfDataTable1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfDataTable2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown4);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown5);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numNodes);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown6);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numFiles1);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.fileEntriesOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.sizeOfStringTable);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.stringTableOffset);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.numFiles2);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown8);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            buffer = BitConverter.GetBytes(header.unknown9);
            Array.Reverse(buffer);
            filestreamWriter.Write(buffer, 0, buffer.Length);

            Console.WriteLine("Writing nodes...");
            //Write each of the nodes
            foreach (Node currentNode in nodes)
            {
                Console.WriteLine("Writing " + currentNode.type);
                binWriter.Write(currentNode.type[0]);
                if (currentNode.type.Length > 1)       //Incase the dirname is only 1 char long
                    binWriter.Write(currentNode.type[1]);
                else
                    filestreamWriter.WriteByte(0x20);
                if (currentNode.type.Length > 2)       //Incase the dirname is only 2 char long
                    binWriter.Write(currentNode.type[2]);
                else
                    filestreamWriter.WriteByte(0x20);
                if (currentNode.type.Length == 4)       //Incase the dirname is only 3 char long
                    binWriter.Write(currentNode.type[3]);
                else
                    filestreamWriter.WriteByte(0x20);

                buffer = BitConverter.GetBytes(currentNode.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.foldernameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.numFileEntries);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
                buffer = BitConverter.GetBytes(currentNode.firstFileEntryOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the file entries at their correct offset
            while (filestreamWriter.Position < (header.fileEntriesOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write all the file entries
            foreach (FileEntry entry in fileEntries)
            {
                Console.WriteLine(String.Format("Writing fileEntry {0:X6}",entry.filenameOffset));

                buffer = BitConverter.GetBytes(entry.id);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.filenameHash);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.unknown2);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.filenameOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.dataOffset);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.dataSize);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);

                buffer = BitConverter.GetBytes(entry.zero);
                Array.Reverse(buffer);
                filestreamWriter.Write(buffer, 0, buffer.Length);
            }

            //Pad out the file to get the string table at its correct offset

            while (filestreamWriter.Position < (header.stringTableOffset + 32))
            {
               filestreamWriter.WriteByte(0x00);
            }

            //Write string table
            Encoding enc = Encoding.UTF8;
            binWriter.Write(enc.GetBytes(stringTable));

            //Pad out the file to get the data table at its correct offset
            while (filestreamWriter.Position < (header.dataStartOffset + 32))
            {
                filestreamWriter.WriteByte(0x00);
            }

            //Write files data
            foreach (byte[] file in filesData)
            {
                Console.WriteLine("Dumping file data...");
                buffer = file;
                filestreamWriter.Write(buffer, 0, buffer.Length);
                while ((filestreamWriter.Position % 32) != 0)//Pad out the data so the next file begins on a 0-based multiple of 32
                    filestreamWriter.WriteByte(0x00);
            }
            for (int pad = 0; pad < numOfPaddingBytes; pad++)//Write the bytes neccessary to make the entire file divisble by 32
                filestreamWriter.WriteByte(0x00);

            binWriter.Close();
            filestreamWriter.Close();

            Console.WriteLine("Packed and good to go!");
        }