/// <summary> /// Returns a reference to a decompressed file /// </summary> /// <param name="record">The DMA address used to reference the file</param> /// <returns></returns> protected RomFile GetFile(FileRecord record) { MemoryStream ms; byte[] data; byte[] decompressedData; if (record.VirtualAddress == CachedFileAddress) { ms = new MemoryStream(CachedFile); return(new RomFile(record, ms, Version)); } using (FileStream fs = new FileStream(RomLocation, FileMode.Open, FileAccess.Read)) { data = new byte[record.DataAddress.Size]; fs.Position = record.DataAddress.Start; fs.Read(data, 0, (int)record.DataAddress.Size); if (record.IsCompressed) { ms = new MemoryStream(data); decompressedData = Yaz0.Decode(ms, (int)(record.DataAddress.Size)); } else { decompressedData = data; } } CachedFile = decompressedData; ms = new MemoryStream(decompressedData); CachedFileAddress = record.VirtualAddress; return(new RomFile(record, ms, Version)); }
/// <summary> /// Loads an archive into a <see cref="VirtualFilesystemDirectory"/>, automatically de-compressing the archive if required. /// /// </summary> /// <param name="filePath">Filepath of file to (optionally) decompress and load.</param> /// <returns><see cref="VirtualFilesystemDirectory"/> containing the contents, or null if filepath is not a valid archive.</returns> public static VirtualFilesystemDirectory LoadArchive(string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath", "Cannot load archive from empty file path!"); } if (!File.Exists(filePath)) { throw new ArgumentException("Cannot load archive from non-existant file!", "filePath"); } MemoryStream decompressedFile = null; using (EndianBinaryReader fileReader = new EndianBinaryReader(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Endian.Big)) { // Read the first 4 bytes to see if it's a compressed file (Yaz0) or a plain RARC file. uint fileMagic = fileReader.ReadUInt32(); fileReader.BaseStream.Position = 0L; // Reset to the start so that the next thing to read it is at the start like it expects. switch (fileMagic) { case 0x59617A30: // Yaz0 Compression decompressedFile = Yaz0.Decode(fileReader); break; case 0x59617930: // Yay0 Compression decompressedFile = Yay0.Decode(fileReader); break; case 0x52415243: // RARC - Uncompressed decompressedFile = new MemoryStream((int)fileReader.BaseStream.Length); fileReader.BaseStream.CopyTo(decompressedFile); // Copying modifies the decompressedFile's read head (places it at new location) so we rewind. decompressedFile.Position = 0L; break; default: throw new NotImplementedException(string.Format("Unknown magic: {0}. If this is a Nintendo archive, open an Issue on GitHub!", fileMagic.ToString("X8"))); } } // Not an archive we know how to handle. if (decompressedFile == null) { return(null); } // Decompress the archive into the folder. It'll generate a sub-folder with the Archive's ROOT name. Archive rarc = new Archive(); using (EndianBinaryReader reader = new EndianBinaryReader(decompressedFile, Endian.Big)) { return(rarc.ReadFile(reader)); } }
private void UpdateModel() { // Loads the necessary information about which figurine model to load dynamically from the REL and the DOL. m_actorMeshes = WResourceManager.LoadActorResource("Figurine Stand"); int modelFileID; int modelArcIndex; int figurineIndex = (int)WhichFigurine; string figurine_rel_path = Path.Combine(WSettingsManager.GetSettings().RootDirectoryPath, "files", "rels/d_a_obj_figure.rel"); MemoryStream figurine_rel_data = null; using (EndianBinaryReader reader = new EndianBinaryReader(File.ReadAllBytes(figurine_rel_path), Endian.Big)) { figurine_rel_data = Yaz0.Decode(reader); } using (EndianBinaryReader reader = new EndianBinaryReader(figurine_rel_data, Endian.Big)) { int l_figure_dat_entry_offset = l_figure_dat_tbl_offset + figurineIndex * 0xC; modelFileID = reader.ReadInt32At(l_figure_dat_entry_offset + 0x00); modelArcIndex = reader.ReadInt32At(l_figure_dat_entry_offset + 0x08); } if (modelArcIndex == -1) { string main_dol_path = Path.Combine(WSettingsManager.GetSettings().RootDirectoryPath, "sys", "main.dol"); using (FileStream strm = new FileStream(main_dol_path, FileMode.Open, FileAccess.Read)) { EndianBinaryReader reader = new EndianBinaryReader(strm, Endian.Big); long l_CharaData_entry_address = l_CharaData_address + figurineIndex * 0x12; long l_CharaData_entry_offset = DOL.AddressToOffset(l_CharaData_entry_address, reader); modelArcIndex = reader.ReadByteAt(l_CharaData_entry_offset + 0x10); } } var arc_name = l_arcname_tbl[modelArcIndex]; string arc_path = Path.Combine(WSettingsManager.GetSettings().RootDirectoryPath, "files", "res/Object/", arc_name + ".arc"); if (File.Exists(arc_path)) { VirtualFilesystemDirectory model_arc = ArchiveUtilities.LoadArchive(arc_path); if (model_arc.FindByID((ushort)modelFileID) != null) { var figurine_model = WResourceManager.LoadModelFromVFS(model_arc, fileID: (ushort)modelFileID); figurine_model.SetOffsetTranslation(new Vector3(0, 100, 0)); m_actorMeshes.Add(figurine_model); } } }
/// <summary> /// Loads an archive into a <see cref="VirtualFilesystemDirectory"/>, automatically de-compressing the archive if required. /// </summary> /// <param name="filePath">Filepath of file to decompress and load.</param> /// <returns><see cref="VirtualFilesystemDirectory"/> containing the contents, or null if not an archive.</returns> public static VirtualFilesystemDirectory LoadArchive(string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath", "Cannot load archive from empty file path!"); } if (!File.Exists(filePath)) { throw new ArgumentException("Cannot load archive from non-existant file!", "filePath"); } MemoryStream decompressedFile = null; using (EndianBinaryReader fileReader = new EndianBinaryReader(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Endian.Big)) { // Read the first 4 bytes to see if it's a compressed file (Yaz0) or a plain RARC file. uint fileMagic = fileReader.ReadUInt32(); fileReader.BaseStream.Position = 0L; // Reset to the start so that the next thing to read it is at the start like it expects. if (fileMagic == 0x59617A30) // Yaz0 { Yaz0 yaz0 = new Yaz0(); decompressedFile = yaz0.Decode(fileReader); } else if (fileMagic == 0x52415243) // RARC { // Copy the fileReader stream to a new memorystream. decompressedFile = new MemoryStream((int)fileReader.BaseStream.Length); fileReader.BaseStream.CopyTo(decompressedFile); decompressedFile.Position = 0L; } } // Not an archive we know how to handle. if (decompressedFile == null) { return(null); } // Decompress the archive into the folder. It'll generate a sub-folder with the Archive's ROOT name. RARC rarc = new RARC(); using (EndianBinaryReader reader = new EndianBinaryReader(decompressedFile, Endian.Big)) { return(rarc.ReadFile(reader)); } }
/// <summary> /// Loads a file into a <see cref="EndianBinaryReader"/>, automatically de-compressing the file if required. /// Throws an exception if the filepath to the file is not valid. /// </summary> /// <param name="filePath">Filepath of file to (optionally) decompress and load.</param> /// <returns><see cref="EndianBinaryReader"/> containing the contents.</returns> public static EndianBinaryReader LoadFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath", "Cannot load archive from empty file path!"); } if (!File.Exists(filePath)) { throw new ArgumentException("Cannot load archive from non-existant file!", "filePath"); } MemoryStream decompressedFile = null; using (EndianBinaryReader fileReader = new EndianBinaryReader(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Endian.Big)) { // Read the first 4 bytes to see if it's a compressed file (Yaz0, Yay0, etc.) uint fileMagic = fileReader.ReadUInt32(); fileReader.BaseStream.Position = 0L; // Reset to the start so that the next thing to read it is at the start like it expects. switch (fileMagic) { case 0x59617A30: // Yaz0 Compression decompressedFile = Yaz0.Decode(fileReader); break; case 0x59617930: // Yay0 Compression decompressedFile = Yay0.Decode(fileReader); break; default: // Uncompressed decompressedFile = new MemoryStream((int)fileReader.BaseStream.Length); fileReader.BaseStream.CopyTo(decompressedFile); // CopyTo modifies the decompressedFile's read head (places it at new location) so we rewind. decompressedFile.Position = 0L; break; } } // Return the decompressed file return(new EndianBinaryReader(decompressedFile, Endian.Big)); }
private static J3D LoadModelFromResource(WActorResource.ModelResource res, string archive) { J3D j3d = null; if (string.IsNullOrEmpty(res.Path) || string.IsNullOrEmpty(archive)) { return(null); } string archivePath = Path.Combine(WSettingsManager.GetSettings().RootDirectoryPath, "files", "res/Object/", archive + ".arc"); if (!File.Exists(archivePath)) { return(null); } VirtualFilesystemDirectory model_arc = ArchiveUtilities.LoadArchive(archivePath); VirtualFilesystemFile archiveFile = model_arc.GetFileAtPath(res.Path); if (archiveFile == null) { Console.WriteLine("LoadActorByName failed because the specified path \"{0}\" does not exist in archive \"{1}\"!", res.Path, archive); return(null); } byte[] j3dData = archiveFile.Data; j3d = new J3D(archiveFile.Name); using (EndianBinaryReader reader = new EndianBinaryReader(j3dData, Endian.Big)) j3d.LoadFromStream(reader, WSettingsManager.GetSettings().DumpTextures, WSettingsManager.GetSettings().DumpShaders); if (res.Position != null) { j3d.SetOffsetTranslation((Vector3)res.Position); } if (res.Rotation != null) { j3d.SetOffsetRotation((Vector3)res.Rotation); } if (res.Scale != null) { j3d.SetOffsetScale((Vector3)res.Scale); } j3d.SetHardwareLight(0, m_mainLight); j3d.SetHardwareLight(1, m_secondaryLight); j3d.SetTextureOverride("ZBtoonEX", "resources/textures/ZBtoonEX.png"); j3d.SetTextureOverride("ZAtoon", "resources/textures/ZAtoon.png"); if (res.Animations == null) { res.Animations = new WActorResource.AnimationResource[0]; } foreach (var anim in res.Animations) { VirtualFilesystemDirectory anim_arc = model_arc; if (!string.IsNullOrEmpty(anim.ArchiveName)) { string anim_arc_path = Path.Combine(WSettingsManager.GetSettings().RootDirectoryPath, "files", "res/Object/", anim.ArchiveName + ".arc"); if (!File.Exists(anim_arc_path)) { return(null); } anim_arc = ArchiveUtilities.LoadArchive(anim_arc_path); } VirtualFilesystemFile anim_file = anim_arc.GetFileAtPath(anim.Path); if (anim_file == null) { continue; } byte[] anim_data = anim_file.Data; // Decompress the file if necessary if (anim_data[0] == 'Y') { MemoryStream decompressed_data = null; using (EndianBinaryReader decompressor = new EndianBinaryReader(anim_data, Endian.Big)) { decompressed_data = Yaz0.Decode(decompressor); } anim_data = decompressed_data.ToArray(); } switch (anim.Type) { case "bck": BCK loaded_bck = new BCK(anim_file.Name); using (EndianBinaryReader reader = new EndianBinaryReader(anim_data, Endian.Big)) loaded_bck.LoadFromStream(reader); j3d.BoneAnimations.Add(loaded_bck); j3d.SetBoneAnimation(anim_file.Name); loaded_bck.Tick(anim.StartTime); if (anim.PausedOnLoad) { loaded_bck.Pause(); } break; case "btk": BTK loaded_btk = new BTK(anim_file.Name); using (EndianBinaryReader reader = new EndianBinaryReader(anim_data, Endian.Big)) loaded_btk.LoadFromStream(reader); j3d.MaterialAnimations.Add(loaded_btk); j3d.SetMaterialAnimation(anim_file.Name); loaded_btk.Tick(anim.StartTime); if (anim.PausedOnLoad) { loaded_btk.Pause(); } break; case "brk": BRK loaded_brk = new BRK(anim_file.Name); using (EndianBinaryReader reader = new EndianBinaryReader(anim_data, Endian.Big)) loaded_brk.LoadFromStream(reader); j3d.RegisterAnimations.Add(loaded_brk); j3d.SetRegisterAnimation(anim_file.Name); loaded_brk.Tick(anim.StartTime); if (anim.PausedOnLoad) { loaded_brk.Pause(); } break; case "bmt": BMT loaded_bmt = new BMT(anim_file.Name); using (EndianBinaryReader reader = new EndianBinaryReader(anim_data, Endian.Big)) loaded_bmt.LoadFromStream(reader); j3d.ExternalMaterials.Add(loaded_bmt); j3d.SetExternalMaterial(anim_file.Name); if (loaded_bmt.MAT3 != null) { // a hack to get bmts working Material dummyMat = null; j3d.AssignVertexAttributesToMaterialsRecursive(j3d.INF1Tag.HierarchyRoot, ref dummyMat, loaded_bmt.MAT3); j3d.GenerateShadersForMaterials(loaded_bmt.MAT3); } break; default: break; } } j3d.Tick(1 / (float)60); if (res.ChildModels == null) { res.ChildModels = new WActorResource.ModelResource[0]; } foreach (var childRes in res.ChildModels) { var childJ3d = LoadModelFromResource(childRes, archive); j3d.AddChildModel(childJ3d, childRes.ParentJointName); } return(j3d); }
private static void ExtractArchive(string outputFolder, string filePath) { if (!File.Exists(filePath)) { Console.WriteLine("Warning: Tried to extract archive from filePath \"{0}\" but not a file!", filePath); return; } if (m_verboseOutput) { Console.Write("Extracting archive {0}... ", Path.GetFileName(filePath)); } try { MemoryStream decompressedFile = null; using (EndianBinaryReader fileReader = new EndianBinaryReader(File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Endian.Big)) { // Read the first 4 bytes to see if it's a compressed file (Yaz0) or a plain RARC file. uint fileMagic = fileReader.ReadUInt32(); fileReader.BaseStream.Position = 0L; // Reset to the start so that the next thing to read it is at the start like it expects. if (fileMagic == 0x59617A30) // Yaz0 { if (m_verboseOutput) { Console.Write("Archive compressed with Yaz0, decompressing... "); } decompressedFile = Yaz0.Decode(fileReader); } if (fileMagic == 0x59617930) // Yay0 { if (m_verboseOutput) { Console.Write("Archive compressed with Yay0, decompressing... "); } decompressedFile = Yay0.Decode(fileReader); } else if (fileMagic == 0x52415243) // RARC { // Copy the fileReader stream to a new memorystream. decompressedFile = new MemoryStream((int)fileReader.BaseStream.Length); fileReader.BaseStream.CopyTo(decompressedFile); decompressedFile.Position = 0L; } } if (decompressedFile == null) { if (m_verboseOutput) { Console.WriteLine("Skipping archive, not a Yaz0 or RARC file."); } return; } // Decompress the archive into the folder. It'll generate a sub-folder with the Archive's ROOT name. Archive rarc = new Archive(); using (EndianBinaryReader reader = new EndianBinaryReader(decompressedFile, Endian.Big)) { VirtualFilesystemDirectory root = rarc.ReadFile(reader); if (m_printFS) { PrintFileSystem(root); } // Many archives use the same internal root name, which causes a conflict when they export. // To solve this, we use the file name of the file as the root name, instead of the internal // name. if (!m_useInternalNames) { root.Name = Path.GetFileNameWithoutExtension(filePath); } // Write it to disk. root.ExportToDisk(outputFolder); } if (m_verboseOutput) { Console.WriteLine("Completed."); } } catch (Exception ex) { Console.WriteLine("Caught Exception: " + ex.ToString()); m_wasError = true; } }