public VirtualFilesystemDirectory ReadFile(EndianBinaryReader reader) { if (reader.ReadUInt32() != 0x52415243) // "RARC" throw new InvalidDataException("Invalid Magic, not a RARC File"); uint fileSize = reader.ReadUInt32(); reader.SkipUInt32(); // Unknown uint dataOffset = reader.ReadUInt32() + 0x20; reader.Skip(16); // Unknown - 4 unsigned ints uint numNodes = reader.ReadUInt32(); reader.Skip(8); // Unknown - 2 unsigned ints uint fileEntryOffset = reader.ReadUInt32() + 0x20; reader.SkipUInt32(); // Unknown uint stringTableOffset = reader.ReadUInt32() + 0x20; reader.Skip(8); // Unknown - 2 unsigned ints. // Read all of the node headers. Node[] nodes = new Node[numNodes]; for (int i = 0; i < numNodes; i++) { nodes[i] = new Node { Type = new string(reader.ReadChars(4)), Name = ReadStringAtOffset(reader, stringTableOffset, reader.ReadUInt32()), NameHashcode = reader.ReadUInt16(), Entries = new FileEntry[reader.ReadUInt16()], FirstFileOffset = reader.ReadUInt32() }; } // Create a virtual directory for every folder within the ARC before we process any of them. List<VirtualFilesystemDirectory> allDirs = new List<VirtualFilesystemDirectory>(nodes.Length); foreach (Node node in nodes) { VirtualFilesystemDirectory vfDir = new VirtualFilesystemDirectory(node.Name); allDirs.Add(vfDir); } for (int k = 0; k < nodes.Length; k++) { Node node = nodes[k]; VirtualFilesystemDirectory curDir = allDirs[k]; for (int i = 0; i < node.Entries.Length; i++) { // Jump to the entry's offset in the file. reader.BaseStream.Position = fileEntryOffset + ((node.FirstFileOffset + i) * 0x14); // 0x14 is the size of a File Entry in bytes node.Entries[i] = new FileEntry(); node.Entries[i].ID = reader.ReadUInt16(); node.Entries[i].NameHashcode = reader.ReadUInt16(); node.Entries[i].Type = reader.ReadByte(); reader.SkipByte(); // Padding node.Entries[i].Name = ReadStringAtOffset(reader, stringTableOffset, reader.ReadUInt16()); // Skip these ones cause I don't know how computers work. if (node.Entries[i].Name == "." || node.Entries[i].Name == "..") continue; uint entryDataOffset = reader.ReadUInt32(); uint dataSize = reader.ReadUInt32(); // If it's a directory, then entryDataOffset contains the index of the parent node if (node.Entries[i].IsDirectory) { node.Entries[i].SubDirIndex = entryDataOffset; var newSubDir = allDirs[(int)entryDataOffset]; curDir.Children.Add(newSubDir); } else { node.Entries[i].Data = reader.ReadBytesAt(dataOffset + entryDataOffset, (int)dataSize); string fileName = Path.GetFileNameWithoutExtension(node.Entries[i].Name); string extension = Path.GetExtension(node.Entries[i].Name); var vfFileContents = new VirtualFileContents(node.Entries[i].Data); VirtualFilesystemFile vfFile = new VirtualFilesystemFile(fileName, extension, vfFileContents); curDir.Children.Add(vfFile); } reader.SkipInt32(); // Padding } } // The ROOT directory should always be the first node. We don't have access to the node's TYPE anymore // so we're going to assume its always the first one listed. return allDirs.Count > 0 ? allDirs[0] : null; }
public static ZUD FromStream(EndianBinaryReader reader) { /*===================================================================== ZUD HEADER =====================================================================*/ byte IDCharacter = reader.ReadByte(); byte IDWeapon = reader.ReadByte(); byte IDWeaponCategory = reader.ReadByte(); byte IDWeaponMaterial = reader.ReadByte(); byte IDShield = reader.ReadByte(); byte IDShieldMaterial = reader.ReadByte(); byte unknown = reader.ReadByte(); reader.SkipByte(); UInt32 ptrCharacterSHP = reader.ReadUInt32(); UInt32 lenCharacterSHP = reader.ReadUInt32(); UInt32 ptrWeaponWEP = reader.ReadUInt32(); UInt32 lenWeaponWEP= reader.ReadUInt32(); UInt32 ptrShieldWEP = reader.ReadUInt32(); UInt32 lenShieldWEP = reader.ReadUInt32(); UInt32 ptrCommonSEQ = reader.ReadUInt32(); UInt32 lenCommonSEQ = reader.ReadUInt32(); UInt32 ptrBattleSEQ = reader.ReadUInt32(); UInt32 lenBattleSEQ = reader.ReadUInt32(); /*===================================================================== STREAM READER =====================================================================*/ ZUD zud = new ZUD(); if (lenCharacterSHP != 0) { zud.Character = SHPLoader.FromStream(reader); } if (lenWeaponWEP != 0) { zud.HasWeapon = true; reader.BaseStream.Seek(ptrWeaponWEP, System.IO.SeekOrigin.Begin); zud.Weapon = WEPLoader.FromStream(reader); } if (lenShieldWEP != 0) { zud.HasShield = true; reader.BaseStream.Seek(ptrShieldWEP, System.IO.SeekOrigin.Begin); zud.Shield = WEPLoader.FromStream(reader); } if (lenCommonSEQ != 0) { zud.HasCommon = true; reader.BaseStream.Seek(ptrCommonSEQ, System.IO.SeekOrigin.Begin); zud.Common = SEQLoader.FromStream(reader, zud.Character); } if (lenBattleSEQ != 0) { zud.HasBattle = true; reader.BaseStream.Seek(ptrBattleSEQ, System.IO.SeekOrigin.Begin); zud.Battle = SEQLoader.FromStream(reader, zud.Character); } return zud; }