/// <summary> /// Returns a list of files with the given extension, or an empty list if no files are found. Searches /// all child directories recursively to look for files. /// </summary> /// <param name="extension">File extension (including period, ie: ".arc")</param> /// <returns>List of files matching that extension</returns> public List <VirtualFilesystemFile> FindByExtension(params string[] extensions) { if (extensions.Length == 0) { throw new ArgumentException("You must specify at least one extension", "extensions"); } List <VirtualFilesystemFile> validFiles = new List <VirtualFilesystemFile>(); foreach (var child in Children) { if (child.Type == NodeType.File) { VirtualFilesystemFile file = (VirtualFilesystemFile)child; for (int i = 0; i < extensions.Length; i++) { string extension = extensions[i]; if (string.Compare(file.Extension, extension, System.StringComparison.InvariantCultureIgnoreCase) == 0) { validFiles.Add(file); break; } } } else if (child.Type == NodeType.Directory) { VirtualFilesystemDirectory dir = (VirtualFilesystemDirectory)child; validFiles.AddRange(dir.FindByExtension(extensions)); } } return(validFiles); }
private void ImportFromDiskRecursive(string folder, VirtualFilesystemDirectory dir) { if (!Directory.Exists(folder)) { throw new ArgumentException("You must specify a directory that exists", "folder"); } // For each directory that is a child of the specified folder into ourselves, and then import the contents. DirectoryInfo dirInfo = new DirectoryInfo(folder); foreach (var diskDir in dirInfo.GetDirectories()) { VirtualFilesystemDirectory vfDir = new VirtualFilesystemDirectory(diskDir.Name); dir.Children.Add(vfDir); ImportFromDiskRecursive(diskDir.FullName, vfDir); } foreach (var diskFile in dirInfo.GetFiles()) { using (BinaryReader reader = new BinaryReader(File.Open(diskFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { string fileName = Path.GetFileNameWithoutExtension(diskFile.Name); string fileExt = Path.GetExtension(diskFile.Name); byte[] data = reader.ReadBytes((int)reader.BaseStream.Length); VirtualFilesystemFile vfFile = new VirtualFilesystemFile(fileName, fileExt, new VirtualFileContents(data)); dir.Children.Add(vfFile); } } }
private void ExportToDiskRecursive(string folder, VirtualFilesystemDirectory dir) { // Create the directory that this node represents. // If it's a directory, append the directory name to the folder and onwards! folder = string.Format("{0}{1}/", folder, dir.Name); try { Directory.CreateDirectory(folder); } catch (Exception ex) { Console.WriteLine("Caught exception while trying to create folder {0}: {1}", folder, ex.ToString()); } foreach (var node in dir.Children) { VirtualFilesystemDirectory vfDir = node as VirtualFilesystemDirectory; VirtualFilesystemFile vfFile = node as VirtualFilesystemFile; if (vfDir != null) { ExportToDiskRecursive(folder, vfDir); } else if (vfFile != null) { // However, if it's a file we're going to write it to disk. string filePath = string.Format("{0}{1}{2}", folder, vfFile.Name, vfFile.Extension); try { using (EndianBinaryWriter writer = new EndianBinaryWriter(File.Create(filePath), Endian.Big)) { writer.Write(vfFile.File.GetData()); } } catch (Exception ex) { Console.WriteLine("Caught exception while trying to write file {0}: {1}", filePath, ex.ToString()); } } } }
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 { ID = reader.ReadUInt16(), NameHashcode = reader.ReadUInt16(), Type = reader.ReadByte(), Padding = reader.ReadByte(), 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); } node.Entries[i].ZeroPadding = reader.ReadUInt32(); } } // 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; }
private void ImportFromDiskRecursive(string folder, VirtualFilesystemDirectory dir) { if (!Directory.Exists(folder)) throw new ArgumentException("You must specify a directory that exists", "folder"); // For each directory that is a child of the specified folder into ourselves, and then import the contents. DirectoryInfo dirInfo = new DirectoryInfo(folder); foreach(var diskDir in dirInfo.GetDirectories()) { VirtualFilesystemDirectory vfDir = new VirtualFilesystemDirectory(diskDir.Name); dir.Children.Add(vfDir); ImportFromDiskRecursive(diskDir.FullName, vfDir); } foreach(var diskFile in dirInfo.GetFiles()) { using(BinaryReader reader = new BinaryReader(File.Open(diskFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { string fileName = Path.GetFileNameWithoutExtension(diskFile.Name); string fileExt = Path.GetExtension(diskFile.Name); byte[] data = reader.ReadBytes((int)reader.BaseStream.Length); VirtualFilesystemFile vfFile = new VirtualFilesystemFile(fileName, fileExt, new VirtualFileContents(data)); dir.Children.Add(vfFile); } } }
public Map CreateFromDirectory(WWorld world, EditorCore editorCore, string folderPath) { if (world == null) throw new ArgumentNullException("world", "No world to load map into specified."); if (string.IsNullOrEmpty(folderPath)) throw new ArgumentException("folderPath is null or empty!"); if (!System.IO.Directory.Exists(folderPath)) throw new System.IO.DirectoryNotFoundException("folderPath not found, ensure the directory exists first!"); // Calculate the Map Name from the folderPath - it should be the last segment of the folder path.s System.IO.DirectoryInfo rootFolderInfo = new System.IO.DirectoryInfo(folderPath); string mapName = rootFolderInfo.Name; // Sort the directories in rootFolderInfo into natural order, instead of alphabetical order which solves issues // where room indexes were getting remapped to the wrong one. IEnumerable<System.IO.DirectoryInfo> subFolders = rootFolderInfo.GetDirectories().OrderByNatural(x => x.Name); IEnumerable<System.IO.FileInfo> subFiles = rootFolderInfo.GetFiles().OrderByNatural(x => x.Name); // Maps are stored in two distinct parts. A Stage which encompasses global data for all rooms, and then // one or more rooms. We're going to load both the room and stage into ZArchives and then load the data // stored in them into different data. var archiveFolderMap = new Dictionary<string, VirtualFilesystemDirectory>(); foreach (var dirInfo in subFolders) { VirtualFilesystemDirectory archive = null; string folderName = dirInfo.Name; if (folderName.ToLower().StartsWith("stage")) { archive = new VirtualFilesystemDirectory(folderName); if (archiveFolderMap.ContainsKey("stage")) { WLog.Warning(LogCategory.EditorCore, null, "{0} contains more than one stage archive, ignoring second...", folderPath); continue; } } else if (folderName.ToLower().StartsWith("room")) { archive = new VirtualFilesystemDirectory(folderName); } // sea has LOD folders which don't have the right sub-folder setup, boo. This skips them for now, // maybe later we can add an ArchiveType.LOD. if (archive == null) continue; // Fill the archives with their contents. archive.ImportFromDisk(dirInfo.FullName); archiveFolderMap[folderName.ToLower()] = archive; } // We're also going to try and process the files inside the folder to see if they're archives. foreach (var fileInfo in subFiles) { VirtualFilesystemDirectory archive = WArchiveTools.ArcUtilities.LoadArchive(fileInfo.FullName); // File wasn't a valid RARC archive. if (archive == null) continue; if (archive.Name.ToLower().StartsWith("stage")) { if (archiveFolderMap.ContainsKey("stage")) { WLog.Warning(LogCategory.EditorCore, null, "{0} contains more than one stage archive, ignoring second...", folderPath); continue; } } string arcName = System.IO.Path.GetFileNameWithoutExtension(fileInfo.FullName).ToLower(); archiveFolderMap[arcName] = archive; } Map newMap = new Map(); newMap.Name = mapName; newMap.ProjectFilePath = System.IO.Path.GetDirectoryName(folderPath); var sceneMap = CreateScenesFromArchives(newMap, archiveFolderMap); LoadEntities(newMap, editorCore, sceneMap, world); LoadModels(sceneMap); return newMap; }