public static void CreateNodes(RARC.FileNode n) { Console.WriteLine("Creating Node for " + n.NodeName); string dirName = n.NodeName; dirName = dirName.ToUpper(); for (int c = 0; c < dirName.Length; c++) { if (c == 4) { break; } nodes[numNodesDone].type = nodes[numNodesDone].type + dirName[c]; } nodes[numNodesDone].filenameOffset = (uint)stringTable.Length; stringTable = stringTable + dirName.ToLower() + (char)0x00; int numFiles = n.Files.Count; nodes[numNodesDone].numFileEntries = (ushort)(numFiles + 2); nodes[numNodesDone].firstFileEntryOffset = (uint)totalNumFilesAdded; dirName = n.NodeName; nodes[numNodesDone].foldernameHash = Hash(dirName); numNodesDone++; }
public static int countRARCDirs(RARC.FileNode Root) { int count = 0; foreach (RARC.FileNode n in Root.ChildNodes) { Console.WriteLine("Node: " + n.NodeName); count++; count += countRARCDirs(n); } return(count); }
public static void CreateEntries(RARC.FileNode Root) { CreateFileEntries(Root); CreateNodeEntries(Root); CreateDummyFiles(); foreach (RARC.FileNode n in Root.ChildNodes) { CreateNodes(n); CreateEntries(n); } }
public static int countRARCFiles(RARC.FileNode Root) { int count = 0; foreach (RARC.FileEntry f in Root.Files) { Console.WriteLine("File: " + f.FileName); count++; } foreach (RARC.FileNode n in Root.ChildNodes) { count += countRARCFiles(n); } return(count); }
public static void CreateNodeEntries(RARC.FileNode Root) { foreach (RARC.FileNode n in Root.ChildNodes) { Console.WriteLine("Creating fileEntry for node " + n.NodeName); fileEntries[totalNumFilesAdded].id = 0xFFFF; fileEntries[totalNumFilesAdded].unknown2 = 0x0200; fileEntries[totalNumFilesAdded].filenameOffset = (ushort)0xFFFE; string fileName = n.NodeName; fileEntries[totalNumFilesAdded].filenameHash = Hash(fileName); fileEntries[totalNumFilesAdded].dataOffset = (uint)0xFFFE; fileEntries[totalNumFilesAdded].dataSize = 0x10; totalNumFilesAdded++; } }
public static void CreateFileEntries(RARC.FileNode Root) { foreach (RARC.FileEntry f in Root.Files) { Console.WriteLine("Creating fileEntry for " + f.FileName); fileEntries[totalNumFilesAdded].id = (ushort)totalNumFilesAdded; if (f.FileName.EndsWith(".szs"))//Check if szs file and use right.. marker? { fileEntries[totalNumFilesAdded].unknown2 = 0x9500; } else { fileEntries[totalNumFilesAdded].unknown2 = 0x1100; } fileEntries[totalNumFilesAdded].filenameOffset = (ushort)stringTable.Length; string fileName = f.FileName; stringTable = stringTable + fileName + (char)0x00; fileEntries[totalNumFilesAdded].filenameHash = Hash(fileName); fileEntries[totalNumFilesAdded].dataOffset = lengthOfDataTable; lengthOfDataTable += (uint)f.fileData.Length; //Pad the data table out so new files start at a 0-based address while ((lengthOfDataTable % 16) != 0) { lengthOfDataTable++; } if ((lengthOfDataTable % 32) != 0)//Check the new address is a multiple of 32 and add 16 if not { lengthOfDataTable += 16; } filesData[numFilesWithData] = f.fileData; fileEntries[totalNumFilesAdded].dataSize = (uint)f.fileData.Length; numFilesWithData++; totalNumFilesAdded++; } }
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!"); }