public iPck(DuplicatableStream duplicatableStream, EndianUtils.Endianness e = EndianUtils.Endianness.BigEndian) { using (DuplicatableStream s = duplicatableStream.Duplicate()) { uint magic = s.ReadUInt32(EndianUtils.Endianness.LittleEndian); if (magic != 0x6b635069) { throw new Exception("wrong magic"); } uint count = s.ReadUInt32(e); uint offsetsStart = s.ReadUInt32(e); uint dataStart = s.ReadUInt32(e); s.Position = offsetsStart; uint[] offsets = s.ReadUInt32Array(count, e); s.Position = dataStart; long dataEnd = s.Length - dataStart; Data = new List <byte[]>((int)count); for (uint i = 0; i < count; ++i) { long start = offsets[i]; if (start == 0xffffffffu) { Data.Add(null); } else { long end = FindFileEnd(offsets, i, dataEnd); long len = end - start; s.Position = dataStart + start; Data.Add(s.ReadUInt8Array(len)); } } } }
public void PrintData() { // save point flags, one byte each, 0x00 not visted 0x01 visited byte[] savePointFlags; using (DuplicatableStream stream = Stream.Duplicate()) { savePointFlags = stream.ReadUInt8Array(0x59); } PrintSavePoint(savePointFlags, 0x00, "Fiertia Deck (Docked at Atherum)"); PrintSavePoint(savePointFlags, 0x01, "Atherum"); PrintSavePoint(savePointFlags, 0x02, "Fiertia Hold"); // same flag for both opportunities? PrintSavePoint(savePointFlags, 0x03, "Keiv Moc (Middle)"); PrintSavePoint(savePointFlags, 0x04, "Keiv Moc (Boss)"); PrintSavePoint(savePointFlags, 0x05, "Zaphias (Lower Quarter)"); PrintSavePoint(savePointFlags, 0x06, "Zaphias (Royal Quarter)"); PrintSavePoint(savePointFlags, 0x07, "Zaphias Castle (Prison)"); PrintSavePoint(savePointFlags, 0x08, "Zaphias Castle (Kitchen)"); // 2nd visit only PrintSavePoint(savePointFlags, 0x09, "Zaphias Castle (Hallways)"); // before zagi fight PrintSavePoint(savePointFlags, 0x0A, "Zaphias Castle (Sword Stair)"); PrintSavePoint(savePointFlags, 0x0B, "Zaphias Castle (Big Hall)"); // 2nd visit only, that big room that leads to the sword stair PrintSavePoint(savePointFlags, 0x0C, "Weasand of Cados (Middle)"); PrintSavePoint(savePointFlags, 0x0D, "Weasand of Cados (Exit)"); PrintSavePoint(savePointFlags, 0x0E, "Halure (Inn)"); PrintSavePoint(savePointFlags, 0x0F, "Ghasfarost (Bottom)"); PrintSavePoint(savePointFlags, 0x10, "Ghasfarost (Top)"); PrintSavePoint(savePointFlags, 0x11, "Myorzo (Vacant House)"); PrintSavePoint(savePointFlags, 0x12, "Mt. Temza (Middle)"); PrintSavePoint(savePointFlags, 0x13, "Mt. Temza (Boss)"); PrintSavePoint(savePointFlags, 0x14, "Deidon Hold"); PrintSavePoint(savePointFlags, 0x15, "Northeastern Hypionia"); // aurnion before it's built PrintSavePoint(savePointFlags, 0x16, "Aurnion (Developing)"); PrintSavePoint(savePointFlags, 0x17, "Aurnion (Developed)"); PrintSavePoint(savePointFlags, 0x18, "Caer Bocram"); PrintSavePoint(savePointFlags, 0x19, "Quoi Woods"); PrintSavePoint(savePointFlags, 0x1A, "Dahngrest (Inn)"); PrintSavePoint(savePointFlags, 0x1B, "Ehmead Hill"); PrintSavePoint(savePointFlags, 0x1C, "Erealumen (Middle)"); PrintSavePoint(savePointFlags, 0x1D, "Erealumen (Boss)"); PrintSavePoint(savePointFlags, 0x1E, "Heracles (Near Engine Room)"); PrintSavePoint(savePointFlags, 0x1F, "Heracles (Near Control Room)"); // zagi fight PrintSavePoint(savePointFlags, 0x20, "Zopheir (Boss)"); // 1st visit only PrintSavePoint(savePointFlags, 0x21, "Zopheir (Near Aer Krene)"); // 2nd visit only PrintSavePoint(savePointFlags, 0x22, "Manor of the Wicked"); PrintSavePoint(savePointFlags, 0x23, "Tarqaron (Middle)"); PrintSavePoint(savePointFlags, 0x24, "Tarqaron (Top)"); PrintSavePoint(savePointFlags, 0x25, "Baction B1F"); PrintSavePoint(savePointFlags, 0x26, "Baction B2F"); // both save points on B2F share this flag...? PrintSavePoint(savePointFlags, 0x27, "Mantaic (Inn)"); PrintSavePoint(savePointFlags, 0x28, "Relewiese (Middle)"); PrintSavePoint(savePointFlags, 0x29, "Relewiese (Boss)"); PrintSavePoint(savePointFlags, 0x2A, "Capua Nor (Outside Ragou's Mansion)"); PrintSavePoint(savePointFlags, 0x2B, "Capua Nor (Inn)"); PrintSavePoint(savePointFlags, 0x2C, "Capua Torim (Inn)"); PrintSavePoint(savePointFlags, 0x2D, "Shaikos Ruins"); PrintSavePoint(savePointFlags, 0x2E, "Zaude (Side Entrance)"); PrintSavePoint(savePointFlags, 0x2F, "Zaude (Alexei)"); PrintSavePoint(savePointFlags, 0x30, "Zaude (Yeager)"); PrintSavePoint(savePointFlags, 0x31, "Aspio (Inn)"); PrintSavePoint(savePointFlags, 0x32, "Nordopolica (Inn)"); PrintSavePoint(savePointFlags, 0x33, "Heliord (Inn)"); PrintSavePoint(savePointFlags, 0x34, "Yormgen (Inn)"); PrintSavePoint(savePointFlags, 0x35, "Weasand of Kogorh (Oasis)"); PrintSavePoint(savePointFlags, 0x36, "Weasand of Kogorh (Exit)"); PrintSavePoint(savePointFlags, 0x37, "Egothor Forest"); PrintSavePoint(savePointFlags, 0x38, "Dahngrest Underpass (Oath)"); PrintSavePoint(savePointFlags, 0x39, "Ragou's Mansion"); // basement dungeon midpoint PrintSavePoint(savePointFlags, 0x3A, "Dahngrest Underpass (Exit)"); PrintSavePoint(savePointFlags, 0x3B, "Abysmal Hollow (Aer Krene near Yumanju)"); PrintSavePoint(savePointFlags, 0x3C, "? Abysmal Hollow (Aer Krene near Zaphias)"); PrintSavePoint(savePointFlags, 0x3D, "Abysmal Hollow (Aer Krene near Heliord)"); PrintSavePoint(savePointFlags, 0x3E, "Abysmal Hollow (Aer Krene near Nordopolica)"); PrintSavePoint(savePointFlags, 0x3F, "? Abysmal Hollow (Center)"); PrintSavePoint(savePointFlags, 0x40, "City of the Waning Moon"); PrintSavePoint(savePointFlags, 0x41, "Necropolis of Nostalgia A3"); PrintSavePoint(savePointFlags, 0x42, "Necropolis of Nostalgia A6"); PrintSavePoint(savePointFlags, 0x43, "Necropolis of Nostalgia A9"); PrintSavePoint(savePointFlags, 0x44, "Necropolis of Nostalgia A Bottom"); PrintSavePoint(savePointFlags, 0x45, "Necropolis of Nostalgia B2"); PrintSavePoint(savePointFlags, 0x46, "Necropolis of Nostalgia B5"); PrintSavePoint(savePointFlags, 0x47, "Necropolis of Nostalgia B8"); PrintSavePoint(savePointFlags, 0x48, "Necropolis of Nostalgia B Bottom"); PrintSavePoint(savePointFlags, 0x49, "Necropolis of Nostalgia C3"); PrintSavePoint(savePointFlags, 0x4A, "Necropolis of Nostalgia C6"); PrintSavePoint(savePointFlags, 0x4B, "Necropolis of Nostalgia C9"); PrintSavePoint(savePointFlags, 0x4C, "Necropolis of Nostalgia C Bottom"); PrintSavePoint(savePointFlags, 0x4D, "Necropolis of Nostalgia D3"); PrintSavePoint(savePointFlags, 0x4E, "Necropolis of Nostalgia D6"); PrintSavePoint(savePointFlags, 0x4F, "Necropolis of Nostalgia D9"); PrintSavePoint(savePointFlags, 0x50, "Necropolis of Nostalgia D Bottom"); PrintSavePoint(savePointFlags, 0x51, "Necropolis of Nostalgia E3"); PrintSavePoint(savePointFlags, 0x52, "Necropolis of Nostalgia E6"); PrintSavePoint(savePointFlags, 0x53, "Necropolis of Nostalgia E9"); PrintSavePoint(savePointFlags, 0x54, "Necropolis of Nostalgia E Bottom"); PrintSavePoint(savePointFlags, 0x55, "Necropolis of Nostalgia F3"); PrintSavePoint(savePointFlags, 0x56, "Necropolis of Nostalgia F6"); PrintSavePoint(savePointFlags, 0x57, "Necropolis of Nostalgia F9"); PrintSavePoint(savePointFlags, 0x58, "Necropolis of Nostalgia F Bottom"); }
public override INode GetChildByIndex(long index) { if (index >= 0 && index < Entries.LongLength) { uint entryLoc = Entries[index]; Stream.Position = entryLoc; uint type = Stream.ReadUInt32(Endian); switch (type) { // PC vesperia can't agree with itself whether this is endian-agnostic or not, the JP files have it swapped compared to the EN files... case 0x69733134: case 0x34317369: { Stream.Position = entryLoc + 0x14; uint length = Stream.ReadUInt32(Endian); uint offset = Stream.ReadUInt32(Endian); Stream.Position = entryLoc + 0xbc; byte[] bnsfheader = Stream.ReadUInt8Array(0x30); Stream.Position = Header.StartOfFiles + offset; using (var ms = new MemoryStream()) { ms.Write(bnsfheader); StreamUtils.CopyStream(Stream, ms, length); return(new NubFile(ms.CopyToByteArrayStreamAndDispose(), "bnsf")); } } case 0x64737000: { Stream.Position = entryLoc + 0x14; uint length = Stream.ReadUInt32(Endian); uint offset = Stream.ReadUInt32(Endian); Stream.Position = entryLoc + 0xbc; byte[] dspheader = Stream.ReadUInt8Array(0x60); Stream.Position = Header.StartOfFiles + offset; using (var ms = new MemoryStream()) { ms.Write(dspheader); StreamUtils.CopyStream(Stream, ms, length); return(new NubFile(ms.CopyToByteArrayStreamAndDispose(), "dsp")); } } case 0x61743300: { Stream.Position = entryLoc; byte[] at3header = Stream.ReadUInt8Array(0x100); Stream.Position = entryLoc + 0x14; uint length = Stream.ReadUInt32(Endian); uint offset = Stream.ReadUInt32(Endian); Stream.Position = Header.StartOfFiles + offset; using (var ms = new MemoryStream()) { ms.Write(at3header); StreamUtils.CopyStream(Stream, ms, length); return(new NubFile(ms.CopyToByteArrayStreamAndDispose(), "at3")); } } case 0x76616700: { Stream.Position = entryLoc; byte[] vagheader = Stream.ReadUInt8Array(0xc0); Stream.Position = entryLoc + 0x14; uint length = Stream.ReadUInt32(Endian); uint offset = Stream.ReadUInt32(Endian); Stream.Position = Header.StartOfFiles + offset; using (var ms = new MemoryStream()) { if (Endian == EndianUtils.Endianness.LittleEndian) { // unclear if this needs to be all swapped or just a subset... for (int i = 0; i < 0xc0; i += 4) { ms.WriteByte(vagheader[i + 3]); ms.WriteByte(vagheader[i + 2]); ms.WriteByte(vagheader[i + 1]); ms.WriteByte(vagheader[i + 0]); } } else { ms.Write(vagheader); } ms.WriteUInt64(0); ms.WriteUInt64(0); StreamUtils.CopyStream(Stream, ms, length); return(new NubFile(ms.CopyToByteArrayStreamAndDispose(), "vag")); } } default: Console.WriteLine("Unimplemented nub subtype: 0x" + type.ToString("x8")); return(null); } } return(null); }