/// <summary> /// Checks whether the buffer size for a file about to be loaded is sufficient and /// conditonally returns an address to a new buffer with adequate size. /// </summary> /// <returns>The address of a new buffer for the game to decompress a file to</returns> private static void *CheckBufferSize(int fileIndex, void *addressToDecompressTo, ONEFILE *thisPointer) { if (fileIndex >= 2) { // Get pointer and length. IntPtr onePointer = (IntPtr)thisPointer[0].InternalDataPointer - 0xC; // The start of file pointer is sometimes unused, so we use the InternalDataPointer instead and offset. int fileLength = thisPointer[0].FileLength; // Now the ONE File MemoryONEArchive memoryOneFile = MemoryONEArchive.ParseONEFromMemory(onePointer, fileLength); // Now we estimate the size of it. int actualFileIndex = fileIndex - 2; MemoryONEFile oneFile = memoryOneFile.Files[actualFileIndex]; byte[] oneFileCopy = GameProcess.ReadMemory((IntPtr)oneFile.CompressedDataPointer, oneFile.DataLength); int oneFileLength = Prs.Estimate(ref oneFileCopy); // Check if the size of allocation is sufficient. MemoryAddressDetails addressDetails = Allocator.GetAddressDetails((int)addressToDecompressTo); if (addressDetails.MemorySize < oneFileLength) { // Allocate some new data for me please addressToDecompressTo = (void *)Allocator.Allocate((int)addressToDecompressTo, oneFileLength); } } return(addressToDecompressTo); }
private void SaveFile() { ByteConverter.BigEndian = bigEndian; int addr = (messages.Count + 1) * 4; List <byte> fc = new List <byte>(); Encoding encoding = useSJIS ? jpenc : euenc; List <string> strs = new List <string>(messages.Select(a => Message.ToString(a, textOnlyToolStripMenuItem.Checked))); foreach (string item in strs) { fc.AddRange(ByteConverter.GetBytes(addr)); addr += encoding.GetByteCount(item) + 1; } fc.AddRange(BitConverter.GetBytes(-1)); foreach (string item in strs) { fc.AddRange(encoding.GetBytes(item)); fc.Add(0); } if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { Prs.Compress(fc.ToArray(), filename); } else { File.WriteAllBytes(filename, fc.ToArray()); } }
public ArchiveFile(string path) { byte[] data = File.ReadAllBytes(path); Name = Path.GetFileName(path); CompressedData = Prs.Compress(ref data); RwVersion.RwVersion = (uint)CommonRWVersions.Heroes; }
static void Main(string[] args) { if (args.Length == 0) { Console.Write("Filename: "); args = new string[] { Console.ReadLine().Trim('"') }; } foreach (string filename in args) { byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } string path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filename)), Path.GetFileNameWithoutExtension(filename)); JsonSerializer js = new JsonSerializer(); EventIniData ini; using (TextReader tr = File.OpenText(Path.Combine(path, Path.ChangeExtension(Path.GetFileName(filename), ".json")))) using (JsonTextReader jtr = new JsonTextReader(tr)) ini = js.Deserialize <EventIniData>(jtr); uint key; if (fc[0] == 0x81) { ByteConverter.BigEndian = true; key = 0x8125FE60; } else { ByteConverter.BigEndian = false; key = 0xC600000; } bool battle = ini.Game == Game.SA2B; List <byte> modelbytes = new List <byte>(fc); Dictionary <string, uint> labels = new Dictionary <string, uint>(); foreach (string file in ini.Files.Where(a => a.Key.EndsWith(".sa2mdl", StringComparison.OrdinalIgnoreCase) && HelperFunctions.FileHash(Path.Combine(path, a.Key)) != a.Value).Select(a => a.Key)) { modelbytes.AddRange(new ModelFile(Path.Combine(path, file)).Model.GetBytes((uint)(key + modelbytes.Count), false, labels, out uint _)); } if (battle) { List <byte> motionbytes = new List <byte>(new byte[(ini.Motions.Count + 1) * 8]); Dictionary <string, int> partcounts = new Dictionary <string, int>(ini.Motions.Count); foreach (string file in ini.Files.Where(a => a.Key.EndsWith(".saanim", StringComparison.OrdinalIgnoreCase)).Select(a => a.Key)) { NJS_MOTION motion = NJS_MOTION.Load(Path.Combine(path, file)); motionbytes.AddRange(motion.GetBytes((uint)(key + motionbytes.Count), labels, out uint _)); partcounts.Add(motion.Name, motion.ModelParts); } byte[] mfc = motionbytes.ToArray(); for (int i = 0; i < ini.Motions.Count; i++) { if (ini.Motions[i] == null) { new byte[] { 0xFF, 0xFF, 0xFF, 0xFF } }
private void LoadFile(string filename) { this.filename = filename; byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } ByteConverter.BigEndian = false; uint le = ByteConverter.ToUInt32(fc, 0); ByteConverter.BigEndian = true; uint be = ByteConverter.ToUInt32(fc, 0); if (be > le) { bigEndian = false; } else if (be < le) { bigEndian = true; } ByteConverter.BigEndian = bigEndian; bigEndianGCSteamToolStripMenuItem.Checked = bigEndian; useSJIS = char.ToLowerInvariant(Path.GetFileNameWithoutExtension(filename).Last()) == 'j'; shiftJISToolStripMenuItem.Checked = useSJIS; windows1252ToolStripMenuItem.Checked = !useSJIS; Encoding encoding = useSJIS ? jpenc : euenc; messages.Clear(); int address = 0; int off = ByteConverter.ToInt32(fc, 0); int end = off; bool hasEscape = false; while (off != -1 && address < end) { string str = fc.GetCString(off, encoding); messages.Add(Message.FromString(str)); if (CheckForEscapeCharacter(str)) { hasEscape = true; } address += 4; off = ByteConverter.ToInt32(fc, address); end = Math.Min(off, end); } textOnlyToolStripMenuItem.Checked = !hasEscape; UpdateMessageSelect(); messagePanel.Enabled = false; AddRecentFile(filename); Text = "SA2 Message File Editor - " + Path.GetFileName(filename); findNextToolStripMenuItem.Enabled = false; }
public Event(string filename) { byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } bool battle = false; uint key; if (fc[0] == 0x81) { ByteConverter.BigEndian = true; key = 0x8125FE60; battle = true; } else { ByteConverter.BigEndian = false; key = 0xC600000; } List <NJS_MOTION> motions = null; if (battle) { motions = ReadMotionFile(Path.ChangeExtension(filename, null) + "motion.bin"); } Dictionary <string, NJS_OBJECT> models = new Dictionary <string, NJS_OBJECT>(); int ptr = fc.GetPointer(0x20, key); if (ptr != 0) { int cnt = battle ? 18 : 16; Upgrades = new EventUpgrade[cnt]; for (int i = 0; i < cnt; i++) { Upgrades[i] = new EventUpgrade(fc, ptr, key, models); ptr += EventUpgrade.Size; } } int gcnt = ByteConverter.ToInt32(fc, 8); ptr = fc.GetPointer(0, key); if (ptr != 0) { Scenes = new List <EventScene>(); for (int gn = 0; gn <= gcnt; gn++) { Scenes.Add(new EventScene(fc, ptr, key, battle, models, motions)); ptr += EventScene.Size; } } }
private void Execute() { if (this.compressRadioButton.Checked) { Prs.Compress(this.sourceFileSelector.FileName, this.destinationFileSelector.FileName); } else if (this.decompressRadioButton.Checked) { Prs.Decompress(this.sourceFileSelector.FileName, this.destinationFileSelector.FileName); } }
private void LoadFile(string filename) { this.filename = filename; byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } ByteConverter.BigEndian = false; uint le = ByteConverter.ToUInt32(fc, 0); ByteConverter.BigEndian = true; uint be = ByteConverter.ToUInt32(fc, 0); uint imageBase = 0; if (be > le) { bigEndian = false; imageBase = 0xCBD0000u; } else if (be < le) { bigEndian = true; imageBase = 0x817AFE60u; } ByteConverter.BigEndian = bigEndian; bigEndianGCSteamToolStripMenuItem.Checked = bigEndian; useSJIS = Path.GetFileNameWithoutExtension(filename).Last() == '0'; shiftJISToolStripMenuItem.Checked = useSJIS; windows1252ToolStripMenuItem.Checked = !useSJIS; Encoding encoding = useSJIS ? jpenc : euenc; scenes.Clear(); int address = 0; int id = ByteConverter.ToInt32(fc, 0); while (id != -1) { scenes.Add(new Scene(fc, address, imageBase, encoding)); address += Scene.Size; id = ByteConverter.ToInt32(fc, address); } UpdateSceneSelect(); scenePanel.Enabled = false; AddRecentFile(filename); Text = "SA2 Cutscene Text Editor - " + Path.GetFileName(filename); findNextToolStripMenuItem.Enabled = false; }
private void SaveFile() { ByteConverter.BigEndian = bigEndian; uint addr = (uint)((scenes.Count + 1) * Scene.Size) + (bigEndian ? 0x817AFE60u : 0xCBD0000u); List <byte> fc = new List <byte>(); Encoding encoding = useSJIS ? jpenc : euenc; foreach (Scene scene in scenes) { fc.AddRange(ByteConverter.GetBytes(scene.SceneNumber)); fc.AddRange(ByteConverter.GetBytes(addr)); fc.AddRange(ByteConverter.GetBytes(scene.Messages.Count)); addr += (uint)(scene.Messages.Count * Message.Size); } fc.AddRange(Enumerable.Repeat(byte.MaxValue, 4)); fc.AddRange(Enumerable.Repeat(byte.MinValue, 8)); System.Diagnostics.Debug.Assert(fc.Count == (scenes.Count + 1) * Scene.Size); foreach (Scene scene in scenes) { foreach (Message msg in scene.Messages) { fc.AddRange(ByteConverter.GetBytes(msg.Character)); fc.AddRange(ByteConverter.GetBytes(addr)); addr += (uint)(encoding.GetByteCount(msg.Text) + 1); if (msg.Centered) { ++addr; } } } foreach (Scene scene in scenes) { foreach (Message msg in scene.Messages) { if (msg.Centered) { fc.Add((byte)'\a'); } fc.AddRange(encoding.GetBytes(msg.Text)); fc.Add(0); } } if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { Prs.Compress(fc.ToArray(), filename); } else { File.WriteAllBytes(filename, fc.ToArray()); } }
private void SaveShadowDATONE(string datOneFileName) { byte[] bdtBytes = VisibilityFunctions.ShadowVisibilityFileToArray(visibilityFunctions.ChunkList, bspRenderer.currentShadowFolderNamePrefix); byte[] splineBytes = shadowSplineEditor.ShadowSplinesToByteArray(bspRenderer.currentShadowFolderNamePrefix).ToArray(); Archive shadowDATONE; if (File.Exists(datOneFileName)) { byte[] fileContents = File.ReadAllBytes(datOneFileName); shadowDATONE = Archive.FromONEFile(ref fileContents); } else { shadowDATONE = new Archive(CommonRWVersions.Shadow050); } bool bdtFound = false; bool splFound = false; foreach (var file in shadowDATONE.Files) { if (Path.GetExtension(file.Name).ToLower() == ".bdt") { file.CompressedData = Prs.Compress(ref bdtBytes); bdtFound = true; } else if (file.Name == "PATH.PTP") { file.CompressedData = Prs.Compress(ref splineBytes); splFound = true; } } if (!bdtFound) { ArchiveFile file = new ArchiveFile((bspRenderer.currentShadowFolderNamePrefix + ".bdt").ToUpper(), bdtBytes); shadowDATONE.Files.Add(file); } if (!splFound) { ArchiveFile file = new ArchiveFile("PATH.PTP", splineBytes); shadowDATONE.Files.Add(file); } File.WriteAllBytes(datOneFileName, shadowDATONE.BuildShadowONEArchive(true).ToArray()); }
private static Stream OpenMaybePRSFile(string filepath) { Stream stream = File.OpenRead(filepath); try { var decompressedStream = new MemoryStream(); Prs.Decompress(stream, decompressedStream); stream.Dispose(); stream = decompressedStream; } catch (Exception) { // Not compressed } stream.Position = 0; return(stream); }
/// <summary> /// Replaces the compressed contents of an individual archive file with another file. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void replaceToolStripMenuItem_Click(object sender, EventArgs e) { // Pick file. CommonOpenFileDialog fileDialog = new CommonOpenFileDialog { Title = "Select the file to replace the current file contents with.", InitialDirectory = _lastOpenedDirectory }; // Replace the file if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok) { byte[] newFile = File.ReadAllBytes(fileDialog.FileName); ArchiveFile.CompressedData = Prs.Compress(ref newFile); if (!Properties.Settings.Default.OpenAtCurrentFile) { _lastOpenedDirectory = Path.GetDirectoryName(fileDialog.FileName); } } }
private void btn_DecompressDragDrop_DragDrop(object sender, DragEventArgs e) { // Get files dropped onto button and process them. string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }; Parallel.ForEach(files, file => { byte[] compressedFile = File.ReadAllBytes(file); byte[] decompressedFile = Prs.Decompress(ref compressedFile); string fileName = Path.GetFileName(file); File.WriteAllBytes($"{TempDirectoryName}\\{fileName}", decompressedFile); }); // Open directory Process.Start(TempDirectoryName); }
public static void Build(string filename) { nodenames.Clear(); modelfiles.Clear(); motionfiles.Clear(); byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } string path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filename)), Path.GetFileNameWithoutExtension(filename)); JsonSerializer js = new JsonSerializer(); EventIniData ini; using (TextReader tr = File.OpenText(Path.Combine(path, Path.ChangeExtension(Path.GetFileName(filename), ".json")))) using (JsonTextReader jtr = new JsonTextReader(tr)) ini = js.Deserialize <EventIniData>(jtr); uint key; bool battle = ini.Game == Game.SA2B; bool battlebeta = ini.Game == Game.SA2B; bool dcbeta = ini.Game == Game.SA2; if (fc[0] == 0x81) { if (fc[0x2B] <= 1 && fc[0x2A] == 0) { ByteConverter.BigEndian = true; key = 0x8125FE60; battle = true; } else { ByteConverter.BigEndian = true; key = 0x812FFE60; battlebeta = true; } } else { if ((fc[37] == 0x25) || (fc[38] == 0x22) || ((fc[36] == 0) && ((fc[1] == 0xFE) || (fc[1] == 0xF2) || ((fc[1] == 0x27) && fc[2] == 0x9F)))) { ByteConverter.BigEndian = false; key = 0xC600000; dcbeta = true; } else { ByteConverter.BigEndian = false; key = 0xC600000; } } List <byte> modelbytes = new List <byte>(fc); Dictionary <string, uint> labels = new Dictionary <string, uint>(); foreach (string file in ini.Files.Where(a => a.Key.EndsWith(".sa2mdl", StringComparison.OrdinalIgnoreCase) && HelperFunctions.FileHash(Path.Combine(path, a.Key)) != a.Value).Select(a => a.Key)) { modelbytes.AddRange(new ModelFile(Path.Combine(path, file)).Model.GetBytes((uint)(key + modelbytes.Count), false, labels, new List <uint>(), out uint _)); } if (battle) { foreach (string file in ini.Files.Where(a => a.Key.EndsWith(".sa2bmdl", StringComparison.OrdinalIgnoreCase) && HelperFunctions.FileHash(Path.Combine(path, a.Key)) != a.Value).Select(a => a.Key)) { modelbytes.AddRange(new ModelFile(Path.Combine(path, file)).Model.GetBytes((uint)(key + modelbytes.Count), false, labels, new List <uint>(), out uint _)); } List <byte> motionbytes = new List <byte>(new byte[(ini.Motions.Count + 1) * 8]); Dictionary <string, int> partcounts = new Dictionary <string, int>(ini.Motions.Count); foreach (string file in ini.Files.Where(a => a.Key.EndsWith(".saanim", StringComparison.OrdinalIgnoreCase)).Select(a => a.Key)) { NJS_MOTION motion = NJS_MOTION.Load(Path.Combine(path, file)); motionbytes.AddRange(motion.GetBytes((uint)motionbytes.Count, labels, out uint _)); partcounts.Add(motion.Name, motion.ModelParts); } byte[] mfc = motionbytes.ToArray(); for (int i = 0; i < ini.Motions.Count; i++) { if (ini.Motions[i] == null) { new byte[] { 0xFF, 0xFF, 0xFF, 0xFF } }
/* * Set of constructors. * Self explanatory. */ /// <summary> /// Returns a copy of the current file that has been PRS Decompressed, ready for writing to disk or manipulation. /// </summary> public byte[] DecompressThis() { return(Prs.Decompress(ref this.CompressedData)); }
/// <summary> /// Makes a "dry" run of the PRS decompressor without copying/actual decompressor. /// Gets the size of the decompressed file. /// </summary> public int GetDecompressedDataSize() { return(Prs.Estimate(GetCompressedDataPtr(), FileSize)); }
public static void Split(string filename) { nodenames.Clear(); modelfiles.Clear(); motionfiles.Clear(); Console.WriteLine("Splitting file {0}...", filename); byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } EventIniData ini = new EventIniData() { Name = Path.GetFileNameWithoutExtension(filename) }; string path = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filename)), Path.GetFileNameWithoutExtension(filename))).FullName; uint key; List <NJS_MOTION> motions = null; bool battle; bool dcbeta; if (fc[0] == 0x81) { if (fc[0x2B] <= 0x01 && fc[0x2A] == 0) { Console.WriteLine("File is in GC/PC format."); ByteConverter.BigEndian = true; key = 0x8125FE60; ini.Game = Game.SA2B; battle = true; dcbeta = false; motions = ReadMotionFile(Path.ChangeExtension(filename, null) + "motion.bin"); ini.Motions = motions.Select(a => a?.Name).ToList(); foreach (var mtn in motions.Where(a => a != null)) { motionfiles[mtn.Name] = new MotionInfo(null, mtn); } } else { Console.WriteLine("File is in GC/PC Beta format."); ByteConverter.BigEndian = true; key = 0x812FFE60; ini.Game = Game.SA2B; battle = false; dcbeta = false; } } else { if ((fc[37] == 0x25) || (fc[38] == 0x22) || ((fc[36] == 0) && ((fc[1] == 0xFE) || (fc[1] == 0xF2) || ((fc[1] == 0x27) && fc[2] == 0x9F)))) { Console.WriteLine("File is in DC Beta format."); ByteConverter.BigEndian = false; key = 0xC600000; ini.Game = Game.SA2; battle = false; dcbeta = true; } else { Console.WriteLine("File is in DC format."); ByteConverter.BigEndian = false; key = 0xC600000; ini.Game = Game.SA2; battle = false; dcbeta = false; } } int ptr = fc.GetPointer(0x20, key); if (ptr != 0) { if (!dcbeta) { for (int i = 0; i < (battle ? 18 : 16); i++) { string upnam = upgradenames[i]; string chnam = upnam; switch (i) { case 0: chnam = "Sonic"; break; case 4: chnam = "Shadow"; break; case 6: chnam = "Knuckles"; break; case 12: chnam = "Rouge"; break; case 16: chnam = "Mech Tails"; break; case 17: chnam = "Mech Eggman"; break; } UpgradeInfo info = new UpgradeInfo(); info.RootNode = GetModel(fc, ptr, key, $"{chnam} Root.sa2mdl"); if (info.RootNode != null) { int ptr2 = fc.GetPointer(ptr + 4, key); if (ptr2 != 0) { info.AttachNode1 = $"object_{ptr2:X8}"; } int ptr3 = fc.GetPointer(ptr + 8, key); if (ptr3 != 0) { info.Model1 = GetModel(fc, ptr + 8, key, $"{upnam} Model 1.sa2mdl"); } ptr2 = fc.GetPointer(ptr + 0xC, key); if (ptr2 != 0) { info.AttachNode2 = $"object_{ptr2:X8}"; } ptr3 = fc.GetPointer(ptr + 0x10, key); if (ptr3 != 0) { info.Model2 = GetModel(fc, ptr + 0x10, key, $"{upnam} Model 2.sa2mdl"); } } ini.Upgrades.Add(info); ptr += 0x14; } } else { for (int i = 0; i < 14; i++) { string upnam = upgradebetanames[i]; string chnam = upnam; switch (i) { case 0: chnam = "Sonic"; break; case 4: chnam = "Shadow"; break; case 6: chnam = "Knuckles"; break; case 10: chnam = "Rouge"; break; } UpgradeInfo info = new UpgradeInfo(); info.RootNode = GetModel(fc, ptr, key, $"{chnam} Root.sa2mdl"); if (info.RootNode != null) { int ptr2 = fc.GetPointer(ptr + 4, key); if (ptr2 != 0) { info.AttachNode1 = $"object_{ptr2:X8}"; } int ptr3 = fc.GetPointer(ptr + 8, key); if (ptr3 != 0) { info.Model1 = GetModel(fc, ptr + 8, key, $"{upnam} Model 1.sa2mdl"); } ptr2 = fc.GetPointer(ptr + 0xC, key); if (ptr2 != 0) { info.AttachNode2 = $"object_{ptr2:X8}"; } ptr3 = fc.GetPointer(ptr + 0x10, key); if (ptr3 != 0) { info.Model2 = GetModel(fc, ptr + 0x10, key, $"{upnam} Model 2.sa2mdl"); } } ini.Upgrades.Add(info); ptr += 0x14; } } } else { Console.WriteLine("Event contains no character upgrades."); } ptr = fc.GetPointer(0x18, key); if (ptr != 0) { for (int i = 0; i < 93; i++) { string name = $"object_{ptr:X8}"; if (name != null) { ini.MechParts.Add(i, name); } ptr += 4; } } else { Console.WriteLine("Event contains no mech parts."); } int gcnt = ByteConverter.ToInt32(fc, 8); ptr = fc.GetPointer(0, key); if (ptr != 0) { Console.WriteLine("Event contains {0} scene(s).", gcnt + 1); for (int gn = 0; gn <= gcnt; gn++) { Directory.CreateDirectory(Path.Combine(path, $"Scene {gn + 1}")); SceneInfo scn = new SceneInfo(); int ptr2 = fc.GetPointer(ptr, key); int ecnt = ByteConverter.ToInt32(fc, ptr + 4); if (ptr2 != 0) { Console.WriteLine("Scene {0} contains {1} entit{2}.", gn + 1, ecnt, ecnt == 1 ? "y" : "ies"); for (int en = 0; en < ecnt; en++) { EntityInfo ent = new EntityInfo(); ent.Model = GetModel(fc, ptr2, key, $"Scene {gn + 1}\\Entity {en + 1} Model.sa2mdl"); if (ent.Model != null) { ent.Motion = GetMotion(fc, ptr2 + 4, key, $"Scene {gn + 1}\\Entity {en + 1} Motion.saanim", motions, modelfiles[ent.Model].Model.CountAnimated()); if (ent.Motion != null) { modelfiles[ent.Model].Motions.Add(motionfiles[ent.Motion].Filename); } ent.ShapeMotion = GetMotion(fc, ptr2 + 8, key, $"Scene {gn + 1}\\Entity {en + 1} Shape Motion.saanim", motions, modelfiles[ent.Model].Model.CountMorph()); if (ent.ShapeMotion != null) { modelfiles[ent.Model].Motions.Add(motionfiles[ent.ShapeMotion].Filename); } } if (battle) { ent.GCModel = GetGCModel(fc, ptr2 + 12, key, $"Scene {gn + 1}\\Entity {en + 1} GC Model.sa2bmdl"); ent.ShadowModel = GetModel(fc, ptr2 + 16, key, $"Scene {gn + 1}\\Entity {en + 1} Shadow Model.sa2mdl"); ent.Position = new Vertex(fc, ptr2 + 24); ent.Flags = ByteConverter.ToUInt32(fc, ptr2 + 36); ent.Layer = ByteConverter.ToUInt32(fc, ptr2 + 40); } else { ent.Position = new Vertex(fc, ptr2 + 16); ent.Flags = ByteConverter.ToUInt32(fc, ptr2 + 28); } scn.Entities.Add(ent); ptr2 += battle ? 0x2C : 0x20; } } else { Console.WriteLine("Scene {0} contains no entities.", gn + 1); } ptr2 = fc.GetPointer(ptr + 8, key); if (ptr2 != 0) { int cnt = ByteConverter.ToInt32(fc, ptr + 12); for (int i = 0; i < cnt; i++) { scn.CameraMotions.Add(GetMotion(fc, ptr2, key, $"Scene {gn + 1}\\Camera Motion {i + 1}.saanim", motions, 1)); ptr2 += sizeof(int); } } ptr2 = fc.GetPointer(ptr + 0x18, key); if (ptr2 != 0) { BigInfo big = new BigInfo(); big.Model = GetModel(fc, ptr2, key, $"Scene {gn + 1}\\Big Model.sa2mdl"); if (big.Model != null) { int anicnt = modelfiles[big.Model].Model.CountAnimated(); int ptr3 = fc.GetPointer(ptr2 + 4, key); if (ptr3 != 0) { int cnt = ByteConverter.ToInt32(fc, ptr2 + 8); for (int i = 0; i < cnt; i++) { big.Motions.Add(new string[] { GetMotion(fc, ptr3, key, $"Scene {gn + 1}\\Big Motion {i + 1}a.saanim", motions, anicnt), GetMotion(fc, ptr3 + 4, key, $"Scene {gn + 1}\\Big Motion {i + 1}b.saanim", motions, anicnt) }); ptr3 += 8; } } } big.Unknown = ByteConverter.ToInt32(fc, ptr2 + 12); scn.Big = big; } scn.FrameCount = ByteConverter.ToInt32(fc, ptr + 28); ini.Scenes.Add(scn); ptr += 0x20; } } else { Console.WriteLine("Event contains no scenes."); } ptr = fc.GetPointer(0x1C, key); if (ptr != 0) { ini.TailsTails = GetModel(fc, ptr, key, $"Tails' tails.sa2mdl"); } else { Console.WriteLine("Event does not contain Tails' tails."); } ptr = fc.GetPointer(4, key); if (ptr == 0) { Console.WriteLine("Event does not contain an internal texture list."); } ptr = fc.GetPointer(0xC, key); if (ptr == 0) { Console.WriteLine("Event does not contain texture sizes."); } ptr = fc.GetPointer(0x24, key); if (ptr == 0) { Console.WriteLine("Event does not contain texture animation data."); } if (battle && fc[0x2B] == 0) { Console.WriteLine("Event does not use GC shadow maps."); } if (battle && fc[0x2B] == 1) { Console.WriteLine("Event uses GC shadow maps."); } foreach (var item in motionfiles.Values) { string fn = item.Filename ?? $"Unknown Motion {motions.IndexOf(item.Motion)}.saanim"; string fp = Path.Combine(path, fn); item.Motion.Save(fp); ini.Files.Add(fn, HelperFunctions.FileHash(fp)); } foreach (var item in modelfiles.Values) { string fp = Path.Combine(path, item.Filename); ModelFile.CreateFile(fp, item.Model, item.Motions.ToArray(), null, null, null, item.Format); ini.Files.Add(item.Filename, HelperFunctions.FileHash(fp)); } JsonSerializer js = new JsonSerializer { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }; using (var tw = File.CreateText(Path.Combine(path, Path.ChangeExtension(Path.GetFileName(filename), ".json")))) js.Serialize(tw, ini); }
/// <summary> /// Writes an uncompressed copy of this individual file to disk. /// </summary> /// <returns></returns> public void WriteToFile(string path) { File.WriteAllBytes(path, Prs.Decompress(ref this.CompressedData)); }
/// <summary> /// Decompresses the data to a fixed array of bytes. /// </summary> public byte[] DecompressData() { return(Prs.Decompress(GetCompressedDataPtr(), FileSize)); }
/// <summary> /// Compresses the file (if necessary), retrieving the compressed data corresponding to this file. /// </summary> /// <param name="bufferSize">Size of the compressor search buffer, between 0 - 8191.</param> public byte[] GetCompressedData(int bufferSize = 255) { return(IsDataCompressed ? Data : Prs.Compress(Data, bufferSize)); }
public byte[] Decompress() => Prs.Decompress(FileDataCompressed);
static void Main(string[] args) { if (args.Length == 0) { Console.Write("Filename: "); args = new string[] { Console.ReadLine().Trim('"') }; } foreach (string filename in args) { Console.WriteLine("Splitting file {0}...", filename); byte[] fc; if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { fc = Prs.Decompress(filename); } else { fc = File.ReadAllBytes(filename); } EventIniData ini = new EventIniData() { Name = Path.GetFileNameWithoutExtension(filename) }; string path = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filename)), Path.GetFileNameWithoutExtension(filename))).FullName; uint key; if (fc[0] == 0x81) { Console.WriteLine("File is in GC/PC format."); ByteConverter.BigEndian = true; key = 0x8125FE60; ini.Game = Game.SA2B; } else { Console.WriteLine("File is in DC format."); ByteConverter.BigEndian = false; key = 0xC600000; ini.Game = Game.SA2; } List <string> nodenames = new List <string>(); Dictionary <string, KeyValuePair <string, NJS_OBJECT> > modelfiles = new Dictionary <string, KeyValuePair <string, NJS_OBJECT> >(); int ptr = fc.GetPointer(0x20, key); if (ptr != 0) { for (int i = 0; i < (ini.Game == Game.SA2B ? 18 : 16); i++) { UpgradeInfo info = new UpgradeInfo(); info.RootNode = GetModel(fc, ptr, key, Path.Combine(path, $"Upgrade {i + 1} Root.sa2mdl"), nodenames, modelfiles); if (info.RootNode != null) { int ptr2 = fc.GetPointer(ptr + 4, key); if (ptr2 != 0) { info.AttachNode1 = $"object_{ptr2:X8}"; } info.Model1 = GetModel(fc, ptr + 8, key, Path.Combine(path, $"Upgrade {i + 1} Model 1.sa2mdl"), nodenames, modelfiles); ptr2 = fc.GetPointer(ptr + 0xC, key); if (ptr2 != 0) { info.AttachNode2 = $"object_{ptr2:X8}"; } info.Model2 = GetModel(fc, ptr + 0x10, key, Path.Combine(path, $"Upgrade {i + 1} Model 2.sa2mdl"), nodenames, modelfiles); } ini.Upgrades.Add(info); ptr += 0x14; } } else { Console.WriteLine("Event contains no character upgrades."); } int gcnt = ByteConverter.ToInt32(fc, 8); ptr = fc.GetPointer(0, key); if (ptr != 0) { Console.WriteLine("Event contains {0} group(s).", gcnt + 1); for (int gn = 0; gn <= gcnt; gn++) { GroupInfo info = new GroupInfo(); int ptr2 = fc.GetPointer(ptr, key); int ecnt = ByteConverter.ToInt32(fc, ptr + 4); if (ptr2 != 0) { Console.WriteLine("Group {0} contains {1} entit{2}.", gn + 1, ecnt, ecnt == 1 ? "y" : "ies"); for (int en = 0; en < ecnt; en++) { string name = GetModel(fc, ptr2, key, Path.Combine(path, $"Group {gn + 1} Entity {en + 1} Model.sa2mdl"), nodenames, modelfiles); if (name != null) { info.Entities.Add(name); } ptr2 += ini.Game == Game.SA2B ? 0x2C : 0x20; } } else { Console.WriteLine("Group {0} contains no entities.", gn + 1); } ptr2 = fc.GetPointer(ptr + 0x18, key); if (ptr2 != 0) { info.Big = GetModel(fc, ptr2, key, Path.Combine(path, $"Group {gn + 1} Big Model.sa2mdl"), nodenames, modelfiles); } ini.Groups.Add(info); ptr += 0x20; } } else { Console.WriteLine("Event contains no groups."); } ptr = fc.GetPointer(0x18, key); if (ptr != 0) { for (int i = 0; i < 93; i++) { string name = GetModel(fc, ptr, key, Path.Combine(path, $"Mech Part {i + 1}.sa2mdl"), nodenames, modelfiles); if (name != null) { ini.MechParts.Add(i, name); } ptr += 4; } } else { Console.WriteLine("Event contains no mech parts."); } ptr = fc.GetPointer(0x1C, key); if (ptr != 0) { ini.TailsTails = GetModel(fc, ptr, key, Path.Combine(path, $"Tails tails.sa2mdl"), nodenames, modelfiles); } else { Console.WriteLine("Event does not contain Tails' tails."); } foreach (var item in modelfiles) { ModelFile.CreateFile(item.Value.Key, item.Value.Value, null, null, null, null, null, ModelFormat.Chunk); ini.Files.Add(Path.GetFileName(item.Value.Key), HelperFunctions.FileHash(item.Value.Key)); } IniSerializer.Serialize(ini, Path.Combine(path, Path.ChangeExtension(Path.GetFileName(filename), ".ini"))); } }
/// <summary> /// Decompresses the file (if necessary), retrieving the data corresponding to this file. /// </summary> public byte[] GetUncompressedData() { return(IsDataCompressed ? Prs.Decompress(Data) : Data); }
private static List <MaterialBuildInfo> BuildProceduralMaterials(string baseDirectory, List <Assimp.Material> aiMaterials, string texturePakPath) { var textureArchive = new GvmArchive(); var textureArchiveStream = new MemoryStream(); var textureArchiveWriter = ( GvmArchiveWriter )textureArchive.Create(textureArchiveStream); var textureIdLookup = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase); if (texturePakPath != null && File.Exists(texturePakPath)) { var extension = Path.GetExtension(texturePakPath); var fileStream = ( Stream )File.OpenRead(texturePakPath); if (extension.Equals(".prs", StringComparison.InvariantCultureIgnoreCase)) { try { var decompressedFileStream = new MemoryStream(); Prs.Decompress(fileStream, decompressedFileStream); fileStream.Dispose(); fileStream = decompressedFileStream; } catch (Exception) { // Not compressed } fileStream.Position = 0; } var existingTextureArchive = new GvmArchive(); var existingTextureArchiveReader = ( GvmArchiveReader )existingTextureArchive.Open(fileStream); for (var i = 0; i < existingTextureArchiveReader.Entries.Count; i++) { var entry = existingTextureArchiveReader.Entries[i]; // Make copy of entry stream var entryStreamCopy = new MemoryStream(); entry.Open().CopyTo(entryStreamCopy); entryStreamCopy.Position = 0; var texture = new VrSharp.GvrTexture.GvrTexture(entryStreamCopy); Console.WriteLine(texture.GlobalIndex); entryStreamCopy.Position = 0; // Clean entry name from the added extension var entryName = Path.ChangeExtension(entry.Name, null); textureArchiveWriter.CreateEntry(entryStreamCopy, entryName); textureIdLookup[entryName] = i; } } var materials = new List <MaterialBuildInfo>(); foreach (var aiMaterial in aiMaterials) { var textureName = Path.GetFileNameWithoutExtension(aiMaterial.TextureDiffuse.FilePath).ToLowerInvariant(); if (!textureIdLookup.TryGetValue(textureName, out var textureId)) { textureId = textureIdLookup[textureName] = textureIdLookup.Count; var texturePath = Path.GetFullPath(Path.Combine(baseDirectory, aiMaterial.TextureDiffuse.FilePath)); if (File.Exists(texturePath)) { // Convert texture var texture = new GvrTexture { GlobalIndex = ( uint )(1 + textureId) }; var textureStream = new MemoryStream(); var textureBitmap = new Bitmap(texturePath); texture.Write(textureBitmap, textureStream); textureStream.Position = 0; // Add it textureArchiveWriter.CreateEntry(textureStream, textureName); } } var material = new MaterialBuildInfo { Ambient = AssimpHelper.FromAssimp(aiMaterial.ColorAmbient), Diffuse = AssimpHelper.FromAssimp(aiMaterial.ColorDiffuse), Specular = AssimpHelper.FromAssimp(aiMaterial.ColorSpecular), ClampU = aiMaterial.TextureDiffuse.WrapModeU == Assimp.TextureWrapMode.Clamp, ClampV = aiMaterial.TextureDiffuse.WrapModeV == Assimp.TextureWrapMode.Clamp, FlipU = aiMaterial.TextureDiffuse.WrapModeU == Assimp.TextureWrapMode.Mirror, FlipV = aiMaterial.TextureDiffuse.WrapModeV == Assimp.TextureWrapMode.Mirror, DestinationAlpha = DstAlphaOp.InverseDst, Exponent = 0, FilterMode = FilterMode.Trilinear, MipMapDAdjust = MipMapDAdjust.D050, SourceAlpha = SrcAlphaOp.Src, SuperSample = false, TextureId = (short)textureId, }; materials.Add(material); } // Write texture archive to file textureArchiveWriter.Flush(); textureArchiveStream.Position = 0; if (texturePakPath != null) { // Compress it. var textureArchivePrsStream = new MemoryStream(); Prs.Compress(textureArchiveStream, textureArchivePrsStream); // Save compressed file. textureArchivePrsStream.Position = 0; using (var outFile = File.Create(texturePakPath)) textureArchivePrsStream.CopyTo(outFile); } return(materials); }
public void Compress(byte[] file) { byte[] compressed = Prs.Compress(file, 0x1FFF); byte[] decompressed = Prs.Decompress(compressed); Assert.Equal(file, decompressed); }
public FileBenchmark(byte[] fileData) { FileData = fileData; FileDataCompressed = Prs.Compress(FileData, 0x1FFF); }
public ArchiveFile(string name, byte[] uncompressedData) { Name = name; CompressedData = Prs.Compress(ref uncompressedData); RwVersion.RwVersion = (uint)CommonRWVersions.Heroes; }
/// <summary> /// 压缩文件 /// </summary> /// <param name="compFile"></param> /// <returns></returns> public override byte[] Compress(string file) { return(Prs.Compress(file)); }
public byte[] Compress(int windowSize) => Prs.Compress(FileData, windowSize);
public void GlobalSetup() { // Executed once per each WindowSize FileDataCompressed = Prs.Compress(FileData, WindowSize); }