1
0
mirror of synced 2024-12-01 02:27:22 +01:00

Improve PCK support

This commit is contained in:
KillzXGaming 2019-12-07 17:35:19 -05:00
parent 668a1a5201
commit cf32ba0cb9
2 changed files with 258 additions and 129 deletions

View File

@ -0,0 +1,258 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
public class PCK : TreeNodeFile, IFileFormat, ILeaveOpenOnLoad
{
public FileType FileType { get; set; } = FileType.Archive;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Audio Archive" };
public string[] Extension { get; set; } = new string[] { "*.pck" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
return reader.CheckSignature(4, "AKPK");
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public List<AudioEntry> Entries = new List<AudioEntry>();
public uint Version = 1;
public uint Flags;
public List<LanguageEntry> Languages = new List<LanguageEntry>();
public List<BankEntry> Banks = new List<BankEntry>();
public List<AudioEntry> Sounds = new List<AudioEntry>();
public void Load(System.IO.Stream stream)
{
Text = FileName;
CanSave = false;
using (var reader = new FileReader(stream, true))
{
reader.ReadSignature(4, "AKPK");
//Total size of language, banks, and sound headers
uint HeaderSize = reader.ReadUInt32();
Flags = reader.ReadUInt32();
uint LanguageSize = reader.ReadUInt32();
uint BanksSize = reader.ReadUInt32();
uint SoundsSize = reader.ReadUInt32();
uint SectionSizes = LanguageSize + BanksSize + SoundsSize + 0x10;
if (SectionSizes == HeaderSize)
Version = 1;
else {
Version = 2;
uint Section4 = reader.ReadUInt32();
}
//Parse sections
//Parse language
long LanguagePos = reader.Position;
uint LanguageCount = reader.ReadUInt32();
for (int i = 0; i < LanguageCount; i++)
{
var lang = new LanguageEntry();
uint nameOffset = reader.ReadUInt32(); ;
lang.ID = reader.ReadUInt32();
Languages.Add(lang);
using (reader.TemporarySeek(LanguagePos + nameOffset, System.IO.SeekOrigin.Begin)) {
lang.Name = reader.ReadZeroTerminatedString();
}
}
reader.SeekBegin(LanguagePos + LanguageSize);
//Parse bansk
long banksPos = reader.Position;
uint BanksCount = reader.ReadUInt32();
for (int i = 0; i < BanksCount; i++)
Banks.Add(new BankEntry());
reader.SeekBegin(banksPos + BanksSize);
//Parse sounds
long soundPos = reader.Position;
uint SoundsCount = reader.ReadUInt32();
Console.WriteLine($"SoundsCount {SoundsCount}");
for (int i = 0; i < SoundsCount; i++)
{
var entry = new AudioEntry();
Nodes.Add(entry);
Sounds.Add(entry);
entry.HashID = reader.ReadUInt32();
entry.Alignment = reader.ReadUInt32();
uint size = reader.ReadUInt32();
uint offset = reader.ReadUInt32();
entry.LanguageID = reader.ReadUInt32();
entry.Text = entry.HashID.ToString("X") + ".wem";
entry.AudioData = new SubStream(reader.BaseStream, offset * entry.Alignment, size);
}
reader.SeekBegin(soundPos + SoundsSize);
}
}
public void Unload()
{
}
public void Save(System.IO.Stream stream)
{
using (var writer = new FileWriter(stream)) {
writer.WriteSignature("AKPK");
writer.Write(uint.MaxValue); //reserve total header size for later
writer.Write(Flags);
long sectionSizesPos = writer.Position;
writer.Write(uint.MaxValue); //reserve language header size for later
writer.Write(uint.MaxValue); //reserve bank header size for later
writer.Write(uint.MaxValue); //reserve sound header size for later
if (Version >= 2)
writer.Write(4);
long langPos = writer.Position;
writer.Write(Languages.Count);
for (int i = 0; i < Languages.Count; i++)
{
writer.Write(0);
writer.Write(Languages[i].ID);
}
//Write the strings after
for (int i = 0; i < Languages.Count; i++)
{
writer.WriteUint32Offset(langPos + 4 + (i * 8), langPos);
writer.Write(Languages[i].Name);
}
//Save language section size
writer.WriteSectionSizeU32(sectionSizesPos, langPos, writer.Position);
long banksPos = writer.Position;
//I don't know any files that use banks yet but todo
writer.Write(Banks.Count);
for (int i = 0; i < Banks.Count; i++)
{
}
//Save banks section size
writer.WriteSectionSizeU32(sectionSizesPos + 4, banksPos, writer.Position);
long soundsPos = writer.Position;
writer.Write(Sounds.Count);
for (int i = 0; i < Sounds.Count; i++)
{
writer.Write(Sounds[i].HashID);
writer.Write(Sounds[i].Alignment);
writer.Write((uint)Sounds[i].AudioData.Length);
writer.Write(uint.MaxValue);
writer.Write(Sounds[i].LanguageID);
}
//Save sounds section size
writer.WriteSectionSizeU32(sectionSizesPos + 8, soundsPos, writer.Position);
//Save unknown section as empty
if (Version >= 2)
writer.Write(0);
//Save sound data
for (int i = 0; i < Sounds.Count; i++)
{
writer.WriteUint32Offset((soundsPos + 4) + 12 + (i * 20));
writer.Write(Sounds[i].AudioData.ToBytes());
}
}
}
public class LanguageEntry
{
public uint ID;
public string Name;
}
public class BankEntry
{
}
public class AudioEntry : TreeNodeCustom, IContextMenuNode
{
public AudioEntry()
{
ImageKey = "bfwav";
SelectedImageKey = "bfwav";
}
public uint HashID { get; set; }
public uint Alignment { get; set; }
public uint LanguageID { get; set; }
public System.IO.Stream AudioData { get; set; }
public ToolStripItem[] GetContextMenuItems()
{
List<ToolStripItem> Items = new List<ToolStripItem>();
Items.Add(new ToolStripMenuItem("Export", null, ExportAction, Keys.Control | Keys.E));
return Items.ToArray();
}
private void ExportAction(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.FileName = Text;
sfd.Filter = "Raw Data (*.*)|*.*";
if (sfd.ShowDialog() == DialogResult.OK) {
AudioData.ExportToFile(sfd.FileName);
}
}
public override void OnClick(TreeView treeview)
{
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
if (editor == null)
{
editor = new HexEditor();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadData(AudioData);
}
}
}
}

View File

@ -1,129 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
public class NLG_PCK : TreeNodeFile, IFileFormat
{
public FileType FileType { get; set; } = FileType.Archive;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Audio Archive" };
public string[] Extension { get; set; } = new string[] { "*.pck" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
return reader.CheckSignature(4, "AKPK");
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public List<AudioEntry> Entries = new List<AudioEntry>();
public void Load(System.IO.Stream stream)
{
Text = FileName;
using (var reader = new FileReader(stream))
{
uint magic = reader.ReadUInt32();
uint audioInfoSize = reader.ReadUInt32();
reader.SeekBegin(48);
uint numEntries = reader.ReadUInt32();
uint audioOffset = audioInfoSize + 12;
for (int i = 0; i < numEntries; i++)
{
AudioEntry entry = new AudioEntry();
entry.ImageKey = "bfwav";
entry.SelectedImageKey = "bfwav";
Nodes.Add(entry);
entry.HashID = reader.ReadUInt32();
uint alignment = reader.ReadUInt32();
uint AudioSize = reader.ReadUInt32();
uint unk = reader.ReadUInt32();
reader.ReadUInt32(); //0
entry.Text = entry.HashID.ToString("X") + ".wem";
using (reader.TemporarySeek(audioOffset, System.IO.SeekOrigin.Begin))
{
reader.Align((int)alignment);
entry.AudioData = reader.ReadBytes((int)AudioSize);
audioOffset = (uint)reader.Position;
}
}
}
}
public void Unload()
{
}
public void Save(System.IO.Stream stream)
{
}
public class AudioEntry : TreeNodeCustom, IContextMenuNode
{
public uint HashID { get; set; }
public byte[] AudioData { get; set; }
public ToolStripItem[] GetContextMenuItems()
{
List<ToolStripItem> Items = new List<ToolStripItem>();
Items.Add(new ToolStripMenuItem("Export", null, ExportAction, Keys.Control | Keys.E));
return Items.ToArray();
}
private void ExportAction(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.FileName = Text;
sfd.Filter = "Raw Data (*.*)|*.*";
if (sfd.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllBytes(sfd.FileName, AudioData);
}
}
public override void OnClick(TreeView treeview)
{
HexEditor editor = (HexEditor)LibraryGUI.GetActiveContent(typeof(HexEditor));
if (editor == null)
{
editor = new HexEditor();
LibraryGUI.LoadEditor(editor);
}
editor.Text = Text;
editor.Dock = DockStyle.Fill;
editor.LoadData(AudioData);
}
}
}
}