using LibXom.Streams; using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Linq; using System.Reflection.PortableExecutable; using System.Text; using System.Threading.Tasks; namespace LibW4M.PS2 { public class PsuFile { public PsuFile() { entries = new List(); } private List entries; public PsuFileEntry[] Entires { get { return entries.ToArray(); } } public PsuFileEntry[] Files { get { List tmpList = new List(); foreach (PsuFileEntry entry in entries) { if (entry.EntryType == PsuEntryType.FILE_ENTRY || entry.EntryType == PsuEntryType.SYSTEM_ENTRY) { tmpList.Add(entry); } } return tmpList.ToArray(); } } public PsuFileEntry[] Directorys { get { List tmpList = new List(); foreach (PsuFileEntry entry in entries) { if (entry.EntryType == PsuEntryType.DIRECTORY_ENTRY) { tmpList.Add(entry); } } return tmpList.ToArray(); } } public void CreateDirectory(string directoryName) { this.entries.Add(new PsuFileEntry(PsuEntryType.DIRECTORY_ENTRY, 0x00, DateTime.Now, 0, DateTime.Now, directoryName, null)); this.entries[0].directoryEntries = this.entries.Count - 1; } public void CreateFile(string fileName, byte[] data) { this.entries.Add(new PsuFileEntry(PsuEntryType.FILE_ENTRY, data.Length, DateTime.Now, 0, DateTime.Now, fileName, data)); this.entries[0].directoryEntries = this.entries.Count - 1; } public void CreateSystemFile(string fileName, byte[] data) { this.entries.Add(new PsuFileEntry(PsuEntryType.SYSTEM_ENTRY, data.Length, DateTime.Now, 0, DateTime.Now, fileName, data)); this.entries[0].directoryEntries = this.entries.Count - 1; } public void InitalizePSU(string titleId) { this.entries.Clear(); CreateDirectory(titleId); CreateDirectory("."); CreateDirectory(".."); } public PsuFileEntry GetFileByName(string filename) { foreach(PsuFileEntry entry in this.Files) { if(entry.Filename.Equals(filename, StringComparison.InvariantCulture)) { return entry; } } throw new FileNotFoundException("Cannot find any file named \""+filename+"\" in the PSU."); } public static PsuFile ReadPSU(string psuFilePath) { PsuFile psuFile = new PsuFile(); psuFile.ReadPSU(File.OpenRead(psuFilePath)); return psuFile; } public void WritePSU(Stream psuStream) { using (XomStreamWriter writer = new XomStreamWriter(psuStream)) { foreach (PsuFileEntry fileEntry in this.Entires) { writer.WriteUInt16((ushort)fileEntry.EntryType); writer.Skip(0x02); writer.WriteInt32(fileEntry.Filesize); writer.Skip(0x01); writer.WriteDateTime(fileEntry.CreationDate); writer.WriteUInt16(fileEntry.Sector); writer.Skip(0x07); writer.WriteDateTime(fileEntry.ModifiedDate); writer.Skip(0x20); writer.WriteStrLen(fileEntry.Filename, 0x1C0); if(fileEntry.FileData != Stream.Null) { fileEntry.FileData.Seek(0, SeekOrigin.Begin); fileEntry.FileData.CopyTo(psuStream); writer.WritePadding(0xFF, 0x400 - (fileEntry.Filesize % 0x400)); } } } } public void ReadPSU(Stream psuStream) { using (XomStreamReader reader = new XomStreamReader(psuStream)) { do { // read header PsuEntryType type = (PsuEntryType)reader.ReadUInt16(); reader.Skip(0x02); int size = reader.ReadInt32(); reader.Skip(0x01); DateTime creationDate = reader.ReadDateTime(); ushort sector = reader.ReadUInt16(); reader.Skip(0x07); DateTime modifiedDate = reader.ReadDateTime(); reader.Skip(0x20); string filename = reader.ReadStrLen(0x1C0); if (type == PsuEntryType.FILE_ENTRY || type == PsuEntryType.SYSTEM_ENTRY) { byte[] fileData = reader.ReadBytes(size); reader.Skip(0x400 - (size % 0x400)); this.entries.Add(new PsuFileEntry(type, size, creationDate, sector, modifiedDate, filename, fileData)); } else { this.entries.Add(new PsuFileEntry(type, size, creationDate, sector, modifiedDate, filename, null)); } } while (psuStream.Position < psuStream.Length); } } } }