internal static Darc InsertFiles(Darc orig, string folderName) { string[] fileNames = new string[orig.Entries.Length]; for (int i = 0; i < fileNames.Length; i++) { fileNames[i] = orig.FileNameTable[i].FileName; } string[] files = Directory.GetFiles(folderName, "*", SearchOption.AllDirectories); foreach (string file in files) { FileInfo fi = new FileInfo(file); string fileName = fi.Name; // Get Index of file int index = Array.IndexOf(fileNames, fileName); if (orig.Entries[index].IsFolder) { throw new Exception(file + " is not a valid file to reinsert!"); } Darc.InsertFile(ref orig, index, file); } // Fix Data layout Array.Resize(ref orig.Data, orig.Data.Length % 4 == 0 ? orig.Data.Length : orig.Data.Length + 4 - orig.Data.Length % 4); orig.Header.FileSize = (uint)(orig.Data.Length + orig.Header.FileDataOffset); return(orig); }
internal static bool InsertFile(ref Darc orig, int index, byte[] data) { if (index < 0) { return(false); } try { uint oldLength = orig.Entries[index].DataLength; uint offset = orig.Entries[index].DataOffset - orig.Header.FileDataOffset; int diff = (int)(data.Length - oldLength); // Insert into Data Block byte[] pre = orig.Data.Take((int)offset).ToArray(); byte[] post = orig.Data.Skip((int)(offset + oldLength)).ToArray(); // Reassemble data orig.Data = pre.Concat(data).Concat(post).ToArray(); // Fix Offset references of other files foreach (var x in orig.Entries.Where(x => x.DataOffset >= offset + oldLength)) { x.DataOffset += (uint)diff; } orig.Entries[index].DataLength = (uint)data.Length; orig.Header.FileSize += (uint)diff; return(true); } catch (Exception) { return(false); } }
internal static bool InsertFile(ref Darc orig, int index, string path) { try { return(Darc.InsertFile(ref orig, index, File.ReadAllBytes(path))); } catch (Exception) { return(false); } }
internal static bool Darc2Files(string path, string folderName) { try { return(Darc.Darc2Files(File.ReadAllBytes(path), folderName)); } catch (Exception) { return(false); } }
internal static bool Files2Darc(string folderName, bool delete = false, string originalDarc = null, string outFile = null) { // Save all contents of a folder to a darc. try { byte[] darcData; Darc orig; string root = folderName; if (originalDarc != null) { // Fetch offset of DARC within file. byte[] darc = File.ReadAllBytes(originalDarc); int darcPos = Darc.GetDarCposition(darc); if (darcPos < 0) { return(false); } byte[] origData = darc.Skip(darcPos).ToArray(); orig = new Darc(origData); orig = Darc.InsertFiles(orig, folderName); byte[] newDarc = Darc.SetDarc(orig); darcData = darc.Take(darcPos).Concat(newDarc).ToArray(); } else // no existing darc to get { orig = Darc.GetDarc(folderName); darcData = Darc.SetDarc(orig); } // Fetch final name if not specified outFile = outFile ?? originalDarc ?? new DirectoryInfo(folderName).Name.Replace("_d", "") + ".darc"; if (darcData == null) { return(false); } File.WriteAllBytes(outFile, darcData); if (Directory.Exists(root) && delete) { Directory.Delete(root, true); } return(true); } catch (Exception) { return(false); } }
internal static bool Darc2Files(byte[] darcData, string folderName) { // Save all contents of a DARC to a folder, assuming there's only 1 layer of folders. try { // Clear existing contents string root = folderName; if (Directory.Exists(root)) { Directory.Delete(root, true); } // Create new DARC object from input data Darc darcFile = new Darc(darcData); // Output data for (int i = 2; i < darcFile.FileNameTable.Length;) { bool isFolder = darcFile.Entries[i].IsFolder; if (!isFolder) { return(false); } // uint level = DARC.Entries[i].DataOffset; Only assuming 1 layer of folders. string parentName = darcFile.FileNameTable[i].FileName; Directory.CreateDirectory(Path.Combine(root, parentName)); int nextFolder = (int)darcFile.Entries[i++].DataLength; // Extract all Contents of said folder while (i < nextFolder) { string fileName = darcFile.FileNameTable[i].FileName; int offset = (int)darcFile.Entries[i].DataOffset; int length = (int)darcFile.Entries[i].DataLength; byte[] data = darcFile.Data.Skip((int)(offset - darcFile.Header.FileDataOffset)).Take(length).ToArray(); string outPath = Path.Combine(root, parentName, fileName); File.WriteAllBytes(outPath, data); i++; // Advance to next Entry } } return(true); } catch (Exception) { return(false); } }
// DARC r/w internal static byte[] SetDarc(Darc darc) { // Package DARC into a writable array. using (MemoryStream ms = new MemoryStream()) using (BinaryWriter bw = new BinaryWriter(ms)) { // Write Header bw.Write(Encoding.ASCII.GetBytes(darc.Header.Signature)); bw.Write(darc.Header.Endianness); bw.Write(darc.Header.HeaderSize); bw.Write(darc.Header.Version); bw.Write(darc.Header.FileSize); bw.Write(darc.Header.FileTableOffset); bw.Write(darc.Header.FileTableLength); bw.Write(darc.Header.FileDataOffset); // Write FileTableEntries foreach (FileTableEntry entry in darc.Entries) { bw.Write(entry.NameOffset | (entry.IsFolder ? (uint)1 << 24 : 0)); bw.Write(entry.DataOffset); bw.Write(entry.DataLength); } foreach (NameTableEntry entry in darc.FileNameTable) { bw.Write(Encoding.Unicode.GetBytes(entry.FileName + "\0")); } while (bw.BaseStream.Position < darc.Header.FileDataOffset) { bw.Write((byte)0); } // Write Data bw.Write(darc.Data); return(ms.ToArray()); } }
internal static Darc GetDarc(string folderName) { // Package Folder into a DARC. List <FileTableEntry> entryList = new List <FileTableEntry>(); List <NameTableEntry> nameList = new List <NameTableEntry>(); byte[] data = new byte[0]; uint nameOffset = 6; // 00 00 + 00 2E 00 00 #region Build FileTable/NameTables { // Null First File { entryList.Add(new FileTableEntry { DataOffset = 0, DataLength = 0, IsFolder = true, NameOffset = 0 }); nameList.Add(new NameTableEntry(0, "")); } // "." Second File { entryList.Add(new FileTableEntry { DataOffset = 0, DataLength = 0, IsFolder = true, NameOffset = 2 }); nameList.Add(new NameTableEntry(6, ".")); } foreach (string folder in Directory.GetDirectories(folderName)) { string parentName = new DirectoryInfo(folder).Name; string[] files = Directory.GetFiles(folder); nameList.Add(new NameTableEntry(nameOffset, parentName)); entryList.Add(new FileTableEntry { DataOffset = 1, DataLength = (uint)(files.Length + entryList.Count), IsFolder = true, NameOffset = nameOffset }); nameOffset += (uint)parentName.Length + 2; // Account for null terminator foreach (string file in files) { FileInfo fi = new FileInfo(file); string fileName = fi.Name; nameList.Add(new NameTableEntry(nameOffset, parentName)); entryList.Add(new FileTableEntry { DataOffset = (uint)data.Length, DataLength = (uint)fi.Length, IsFolder = false, NameOffset = nameOffset }); data = data.Concat(File.ReadAllBytes(file)).ToArray(); nameOffset += (uint)fileName.Length + 2; // Account for null terminator } } } #endregion // Compute Necessary DARC information int darcFileCount = nameList.Count; int nameListOffset = darcFileCount * 0xC; int nameListLength = (int)(nameOffset + nameListOffset); int dataOffset = nameListLength % 4 == 0 ? nameListLength : nameListLength + (4 - nameListLength % 4); Array.Resize(ref data, data.Length % 4 == 0 ? data.Length : data.Length + 4 - data.Length % 4); int finalSize = dataOffset + data.Length; // Create New DARC Darc darc = new Darc { Header = { Signature = "darc", Endianness = 0xFEFF, HeaderSize = 0x1C, Version = 1, FileSize = (uint)finalSize, FileTableOffset = 0x1C, FileTableLength = (uint)nameListLength, FileDataOffset = (uint)dataOffset, }, Entries = entryList.ToArray(), FileNameTable = nameList.ToArray(), Data = data, }; // Fix the First two folders to specify the number of files darc.Entries[0].DataLength = (uint)darcFileCount; darc.Entries[1].DataLength = (uint)darcFileCount; // Fix the Data Offset of the files to point to actual destination foreach (FileTableEntry f in darc.Entries.Where(x => !x.IsFolder)) { f.DataOffset += darc.Header.FileDataOffset; } return(darc); }