private short currentBankID = 0; // also runtime -- just for tracking public JIBank loadIBNK(BeBinaryReader binStream, int Base) { var RetIBNK = new JIBank(); binStream.BaseStream.Position = Base; long anchor = 0; // Return / Seekback anchor //binStream.BaseStream.Seek(-4, SeekOrigin.Current); if (binStream.ReadInt32() != IBNK) // Check if first 4 bytes are IBNK { throw new InvalidDataException("Data is not an IBANK"); } var SectionSize = binStream.ReadUInt32(); // Read IBNK Size var IBankID = binStream.ReadInt32(); // Read the global IBankID currentBankID = (short)IBankID; var IBankFlags = binStream.ReadUInt32(); // Flags? binStream.BaseStream.Seek(0x10, SeekOrigin.Current); // Skip Padding anchor = binStream.BaseStream.Position; var Instruments = loadBank(binStream, Base); // Load the instruments RetIBNK.id = IBankID; // Store bankID RetIBNK.Instruments = Instruments; // Store instruments return(RetIBNK); }
private long ReadJARCSizePointer(BeBinaryReader br) { var sectSize = br.ReadUInt32(); return(sectSize + 8); // This is basically taking the section size pointer and adding 8 to it, because the size is always 8 bytes deep. // Adding 8 to this makes it a pointer to the next section relative to the section base :v }
/* * JAIV1 BANK structure * 0x00 int32 0x42414E4B 'BANK'; * 0x04 int32[0xF0] InstrumentPointers * ---- NOTE: If the instrument pointer is 0, then the instrument for that index is NULL! */ public JInstrument[] loadBank(BeBinaryReader binStream, int Base) { if (binStream.ReadUInt32() != BANK) // Check if first 4 bytes are BANK { throw new InvalidDataException("Data is not a BANK"); } var InstrumentPoiners = new int[0xF0]; // Table of pointers for the instruments; var Instruments = new JInstrument[0xF0]; InstrumentPoiners = Helpers.readInt32Array(binStream, 0xF0); // Read instrument pointers. for (int i = 0; i < 0xF0; i++) { binStream.BaseStream.Position = InstrumentPoiners[i] + Base; // Seek to pointer position var type = binStream.ReadInt32(); // Read type binStream.BaseStream.Seek(-4, SeekOrigin.Current); // Seek back 4 bytes to undo header read. currentInstID = (short)i; switch (type) { case INST: Instruments[i] = loadInstrument(binStream, Base); // Load instrument break; case PER2: Instruments[i] = loadPercussionInstrument(binStream, Base); // Load percussion break; default: // no action, we don't know what it is and it won't misalign. break; } } return(Instruments); }
public static byte[] DeSerializeLongString(byte[] buf) { BeBinaryReader br = new BeBinaryReader(new MemoryStream(buf)); uint size = br.ReadUInt32(); byte[] data = br.ReadBytes((int)size); br.Close(); return(data); }
/* * JAIV1 PER2 Structure * 0x00 int32 0x50455232 'PER2' * 0x04 byte[0x84] unused; // the actual f**k? Waste of 0x84 perfectly delicious bytes. * 0x8C *PercussionKey[100] * * PER2 PercussionKey Structure * float pitch; * float volume; * byte[0x8] unused? * int32 velocityRegionCount * VelocityRegion[velocityRegionCount] velocities * */ public JInstrument loadPercussionInstrument(BeBinaryReader binStream, int Base) { var Inst = new JInstrument(); if (binStream.ReadUInt32() != PER2) // Check if first 4 bytes are PER2 { throw new InvalidDataException("Data is not an PER2"); } Inst.Pitch = 1.0f; Inst.Volume = 1.0f; Inst.IsPercussion = true; binStream.BaseStream.Seek(0x84, SeekOrigin.Current); JInstrumentKey[] keys = new JInstrumentKey[100]; int[] keyPointers = new int[100]; keyPointers = Helpers.readInt32Array(binStream, 100); // read the pointers. for (int i = 0; i < 100; i++) // Loop through all pointers. { if (keyPointers[i] == 0) { continue; } binStream.BaseStream.Position = keyPointers[i] + Base; // Set position to key pointer pos (relative to base) var newKey = new JInstrumentKey(); newKey.Pitch = binStream.ReadSingle(); // read the pitch newKey.Volume = binStream.ReadSingle(); // read the volume binStream.BaseStream.Seek(8, SeekOrigin.Current); // runtime values, skip var velRegCount = binStream.ReadInt32(); // read count of regions we have newKey.Velocities = new JInstrumentKeyVelocity[0xff]; // 0xFF just in case. int[] velRegPointers = Helpers.readInt32Array(binStream, velRegCount); var velLow = 0; // Again, these are regions -- see LoadInstrument for this exact code ( a few lines above ) for (int b = 0; b < velRegCount; b++) { binStream.BaseStream.Position = velRegPointers[b] + Base; var breg = readKeyVelRegion(binStream, Base); // Read the vel region. for (int c = 0; c < breg.baseVel - velLow; c++) { // They're velocity regions, so we're going to have a toothy / gappy piano. So we need to span the missing gaps with the previous region config. // This means that if the last key was 4, and the next key was 8 -- whatever parameters 4 had will span keys 4 5 6 and 7. newKey.Velocities[c] = breg; // store the region newKey.Velocities[127] = breg; } velLow = breg.baseVel; // store the velocity for spanning } keys[i] = newKey; } Inst.Keys = keys; return(Inst); }
public static int baa_GetSectionSize(JAIInitSection sect, BeBinaryReader br) { switch (sect.type) { // The following is true for both V1-Type banks case JAIInitSectionType.IBNK: br.BaseStream.Position = sect.start; br.ReadUInt32(); // Skip IBNK header. return(br.ReadInt32() + 8); // next operator is size case JAIInitSectionType.WSYS: br.BaseStream.Position = sect.start; br.ReadUInt32(); // Skip WSYS header. return(br.ReadInt32() + 8); // next operator is size case JAIInitSectionType.UNKNOWN: br.BaseStream.Position = sect.start; br.ReadInt32(); return(br.ReadInt32()); default: return(sect.size); } }
public Save(string name, int slot) { filename = name; BaseOffset = (uint)(0x2590 + slot * 0x68548); var file = File.OpenRead(filename); using (var br = new BeBinaryReader(file)) { br.BaseStream.Position = ONLINE_PROFILE; OnlineName = sjis.GetString(br.ReadBytes(16)); OnlineProfile = br.ReadUInt32(); br.BaseStream.Position = BaseOffset + 8; CreationDate = br.ReadUInt32(); CreationTime = br.ReadUInt32(); HoursPlayed = br.ReadUInt32(); MinutesPlayed = br.ReadUInt32(); br.BaseStream.Position = BaseOffset + INAZUMA_POINT_OFFSET; InazumaPoints = br.ReadUInt32(); br.BaseStream.Position = BaseOffset + PROFILENAME_OFFSET; ProfileName = sjis.GetString(br.ReadBytes(16)); for (var i = 0; i < 412; i++) { // Stats var player = new Player(); br.BaseStream.Position = BaseOffset + STATS_OFFSET + i * 0x3c; player.Stats = new Stats(br); // Moves br.BaseStream.Position = BaseOffset + WAZA_OFFSET + i * 0x22; player.MoveList = new MoveList(br); Players[i] = player; } br.BaseStream.Position = BaseOffset + TEAM_OFFSET; Team = new Team(br); br.BaseStream.Position = BaseOffset + PROFILENAME_OFFSET + 18; Team.Name = sjis.GetString(br.ReadBytes(16)); br.BaseStream.Position = BaseOffset + TEAM_EMBLEM_OFFSET; Team.Emblem = br.ReadInt16(); br.BaseStream.Position = BaseOffset + PROFILE_OFFSET; Profile = br.ReadUInt32(); } }
private JWave loadWave(BeBinaryReader binStream, int Base) { var newWave = new JWave(); binStream.ReadByte(); // First byte unknown? newWave.format = binStream.ReadByte(); // Read wave format, usually 5 newWave.key = binStream.ReadByte(); // Read the base tuning key //Console.WriteLine(newWave.key); binStream.ReadByte(); // fourth byte unknown? newWave.sampleRate = binStream.ReadSingle(); // Read the samplerate newWave.wsys_start = binStream.ReadInt32(); // Read the offset in the AW newWave.wsys_size = binStream.ReadInt32(); // Read the length in the AW newWave.loop = binStream.ReadUInt32() == UInt32.MaxValue ? true : false; // Check if it loops? newWave.loop_start = binStream.ReadInt32(); // Even if looping is disabled, it should still read loops newWave.loop_end = binStream.ReadInt32(); // Sample index of loop end newWave.sampleCount = binStream.ReadInt32(); // Sample count return(newWave); }
/* This class originally had something more clever going on, Zelda Four Swords threw a giant f*****g wrench in my code. */ /* I'd not recommend using it, as it might be removed in the future if the codebase for it doesn't grow. */ public static JAIInitType checkVersion(ref byte[] data) { var JStream = new MemoryStream(data); var JReader = new BeBinaryReader(JStream); var hdr = JReader.ReadUInt32(); if (hdr == 1094803260) // AA_< LITERAL , opening of BAA archive or BAA Format { JReader.Close(); JStream.Close(); return(JAIInitType.BAA); // return BAA type } else { /* PIKMIN BX ARCHIVE */ /* CHECKING FOR BX * This is not 100% accurate, but the likelyhood of something like this actually getting confused with AAF is slim to none. * Considering there's only one game that uses BX. */ JStream.Position = 0; // reset pos; var BXWSOffs = JReader.ReadInt32(); // should point to location in file. if (BXWSOffs < JStream.Length) // check if is within BX { JStream.Position = BXWSOffs; var WSO = JReader.ReadInt32(); if (WSO < JStream.Length) // fall out, not valid { var WSYS = JReader.ReadInt32(); if (WSYS == 0x57535953) // 0x57535953 is literal WSYS { JReader.Close(); // flush / close streams JStream.Close(); // flush and close streams return(JAIInitType.BX); } } } } // * The init type is otherwise AAF. { JReader.Close(); JStream.Close(); return(JAIInitType.AAF); // JAIInitSection v1 doesn't have an identifying header. } }
public static InstructionSet Disassemble(string path) { InstructionSet instructionSet = new InstructionSet(); using (var file = File.Open(path, FileMode.Open)) { using (var reader = new BeBinaryReader(file)) { while (reader.BaseStream.Position != reader.BaseStream.Length) { byte operation = reader.ReadByte(); var parameterSchema = parameterSchemas[operation]; var parameters = new List <TypedNumber>(); for (var i = 0; i < parameterSchema.Length; i++) { var parameter = parameterSchema[i]; switch (parameter) { case ParameterType.size_8: parameters.Add(TypedNumber.TypedByte( reader.ReadByte() )); break; case ParameterType.size_16: parameters.Add(TypedNumber.TypedShort( reader.ReadUInt16() )); break; case ParameterType.size_32: parameters.Add(TypedNumber.TypedInt( reader.ReadUInt32() )); break; } } instructionSet.Add(new Instruction( opcode: operation, parameters: parameters.ToArray() )); } } } return(instructionSet); }
/// <summary> /// Apply patch data from given <see cref="Stream"/> to the ROM. /// </summary> /// <param name="inStream">Input stream.</param> /// <returns><see cref="SHA256"/> hash of the patch.</returns> public static byte[] ApplyPatch(Stream inStream) { try { var aes = Aes.Create(); var hashAlg = new SHA256Managed(); using (var cryptoStream = new CryptoStream(inStream, aes.CreateDecryptor(key, iv), CryptoStreamMode.Read)) using (var hashStream = new CryptoStream(cryptoStream, hashAlg, CryptoStreamMode.Read)) using (var decompressStream = new GZipStream(hashStream, CompressionMode.Decompress)) using (var memoryStream = new MemoryStream()) { // Fully decompress into MemoryStream so that we can access Position to check for end of Stream. decompressStream.CopyTo(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); using var reader = new BeBinaryReader(memoryStream); // Validate patch magic. var magic = reader.ReadUInt32(); ValidateMagic(magic); Span <byte> headerBytes = stackalloc byte[PatchHeader.Size]; while (reader.BaseStream.Position != reader.BaseStream.Length) { // Read header bytes into stack buffer to prevent allocation. reader.ReadExact(headerBytes); var header = PatchHeader.Read(headerBytes); var data = reader.ReadBytes(header.Length); ApplyPatchEntry(header, data); } } return(hashAlg.Hash); } catch { throw new IOException("Failed to apply patch. Patch may be invalid."); } }
public static Image Decode(Stream stream) { var br = new BeBinaryReader(stream, Encoding.Default, leaveOpen: true); ColorMode colorMode = ColorMode.Greyscale; var size = (Width : 0, Height : 0); byte[] data = null; var header = br.ReadBytes(8); var idats = new List <byte[]>(); var running = true; while (running) { var dlen = br.ReadInt32(); var type = Encoding.ASCII.GetString(br.ReadBytes(4)); switch (type) { case "IHDR": size = (br.ReadInt32(), br.ReadInt32()); br.ReadByte(); switch (br.ReadByte()) { case 0: colorMode = ColorMode.Greyscale; break; case 2: colorMode = ColorMode.Rgb; break; case 6: colorMode = ColorMode.Rgba; break; default: throw new NotImplementedException(); } data = new byte[size.Width * size.Height * Image.PixelSize(colorMode)]; br.ReadByte(); br.ReadByte(); br.ReadByte(); break; case "IDAT": idats.Add(br.ReadBytes(dlen)); break; case "IEND": running = false; break; default: br.ReadBytes(dlen); break; } br.ReadUInt32(); } var idata = idats.SelectMany(x => x).ToArray(); using (var ms = new MemoryStream()) using (var zs = new ZlibStream(ms, CompressionMode.Decompress)) { zs.Write(idata, 0, idata.Length); zs.Flush(); ms.Flush(); var tdata = ms.GetBuffer(); var ps = Image.PixelSize(colorMode); var stride = size.Width * ps; for (var y = 0; y < size.Height; ++y) { Array.Copy(tdata, y * stride + y + 1, data, stride * y, stride); switch (tdata[y * stride + y]) { case 0: break; case 1: { for (var x = ps; x < stride; ++x) { data[y * stride + x] = unchecked ((byte)(data[y * stride + x] + data[y * stride + x - ps])); } break; } case 2: { if (y == 0) { break; } for (var x = 0; x < stride; ++x) { data[y * stride + x] = unchecked ((byte)(data[y * stride + x] + data[y * stride + x - stride])); } break; } case 4: { byte Paeth(byte a, byte b, byte c) { int p = a + b - c, pa = p > a ? p - a : a - p, pb = p > b ? p - b : b - p, pc = p > c ? p - c : c - p; return(pa <= pb && pa <= pc ? a : pb <= pc ? b : c); } for (var x = 0; x < stride; ++x) { byte mod = 0; if (x < ps) { if (y > 0) { mod = Paeth(0, data[(y - 1) * stride + x], 0); } } else { mod = y == 0 ? Paeth(data[y * stride + x - ps], 0, 0) : Paeth(data[y * stride + x - ps], data[(y - 1) * stride + x], data[(y - 1) * stride + x - ps]); } data[y * stride + x] = unchecked ((byte)(data[y * stride + x] + mod)); } break; } case byte x: throw new NotImplementedException($"Unsupported filter mode {x}"); } } } return(new Image(colorMode, size, data)); }
public static OfpPortState Parse(this BeBinaryReader br, out OfpPortState b) { b = (OfpPortState)br.ReadUInt32(); return(b); }
private void loadIBNKJaiV2(BeBinaryReader instReader) { long anchor = 0; var BaseAddress = instReader.BaseStream.Position; var current_header = instReader.ReadUInt32(); if (current_header != 0x49424e4b) // Check to see if it equals IBNK { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("0x{0:X}", BaseAddress); throw new InvalidDataException("Scanned header is not an IBNK."); } var IBNKSize = instReader.ReadUInt32(); id = instReader.ReadInt32(); var flags = instReader.ReadUInt32(); // usually 1, determines if the bank is melodic or used for sound effects. Usually the bank is melodic. instReader.BaseStream.Seek(0x10, SeekOrigin.Current); // Skip 16 bytes, always 0x00, please document if wrong. var i = 0; while (true) { anchor = instReader.BaseStream.Position; // Store current section base. i++; // Console.WriteLine("Iteration {0} 0x{1:X}", i,anchor); current_header = instReader.ReadUInt32(); // Console.WriteLine("GOT HD {0:X}", current_header); if (current_header == 0x00) { break; // End of section. } else if (current_header < 0xFFFF) // Read below for explanation { // I've noticed VERY RARELY, that the section pointer is wrong by two bytes. This sucks. So we check if it's less than two full bytes. // If it is, we seek back 2 bytes then read again, and our alignment is fixed :). // of course, this comes after our check to see if it's 0, which indicates end of section instReader.BaseStream.Seek(-2, SeekOrigin.Current); Console.WriteLine("[!] Misalignment detected in IBNK, new position 0x{0:X}", instReader.BaseStream.Position); anchor = instReader.BaseStream.Position; // 3/14/2019, i forgot this. It's S M R T to update your read base. current_header = instReader.ReadUInt32(); Console.WriteLine("New header {0:X}", current_header); } var next_section = ReadJARCSizePointer(instReader); // if that works, go ahead and grab the 'pointer' to the next section. if (current_header < 0xFFFF) { Console.WriteLine("Corrupt IBNK 0x{0:X}", BaseAddress); break; } switch (current_header) { case 0x4F534354: // OSCT case 0x52414E44: // RAND case 0x454E5654: // EVNT case 0x53454E53: // SENS instReader.BaseStream.Position = anchor + next_section; // Skip section. break; case INST: { var NewINST = new Instrument(); var InstCount = instReader.ReadInt32(); NewINST.Keys = new InstrumentKey[0xF0]; for (int instid = 0; instid < InstCount; instid++) { current_header = instReader.ReadUInt32(); var iebase = instReader.BaseStream.Position; if (current_header != Inst) { break; // F**K. } NewINST.oscillator = instReader.ReadInt32(); NewINST.id = instReader.ReadInt32(); instReader.ReadInt32(); // cant figure out what these are. var keyCounts = instReader.ReadInt32(); // How many key regions are in here. int KeyHigh = 0; int KeyLow = 0; for (int k = 0; k < keyCounts; k++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; byte key = instReader.ReadByte(); // Read the key identifierr KeyHigh = key; // Set the highest key to what we just read. instReader.BaseStream.Seek(3, SeekOrigin.Current); // 3 bytes, unused. var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array\ if (VelocityRegionCount > 0x7F) { Console.WriteLine("Alignment is f****d, IBNK load aborted."); Console.WriteLine("E: VelocityRegionCount is too thicc. {0} > 128", VelocityRegionCount); Console.WriteLine("IBASE: 0x{0:X} + 0x{1:X} ({2:X})", anchor, iebase - anchor, (instReader.BaseStream.Position - anchor) - (iebase - anchor)); return; } for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < (VelHigh - VelLow); idx++) // See below for what this is doing { NewKey.keys[(VelLow + idx)] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } } for (int idx = 0; idx < (KeyHigh - KeyLow); idx++) // The keys are gappy. { NewINST.Keys[(KeyLow + idx)] = NewKey; // So we want to interpolate the previous keys across the empty ones, so that way it's a region NewINST.Keys[127] = NewKey; } KeyLow = KeyHigh; // Set our new lowest key to the previous highest } } instReader.BaseStream.Position = anchor + next_section; // SAFETY. break; } case PERC: instReader.BaseStream.Position = anchor + next_section; break; case 0x4C495354: // LIST instReader.BaseStream.Position = anchor + next_section; // Skip section // Explanation: This is just a set of pointers relative to BaseAddress for the instruments, nothing special because we're // already parsing them above. break; default: instReader.BaseStream.Position = anchor + next_section; // Skip section. break; } } }
public static OfpPortFeatures Parse(this BeBinaryReader br, out OfpPortFeatures b) { b = (OfpPortFeatures)br.ReadUInt32(); return(b); }
private void loadIBNKJaiV1(BeBinaryReader instReader) { long anchor = 0; var BaseAddress = instReader.BaseStream.Position; var current_header = 0u; current_header = instReader.ReadUInt32(); // read the first 4 byteas if (current_header != 0x49424e4b) // Check to see if it equals IBNK { throw new InvalidDataException("Scanned header is not an IBNK."); } var size = instReader.ReadUInt32(); id = instReader.ReadInt32(); // Global virtual ID instReader.BaseStream.Seek(0x14, SeekOrigin.Current); // 0x14 bytes always blank current_header = instReader.ReadUInt32(); // We should be reading "BANK" for (int inst_id = 0; inst_id < 0xF0; inst_id++) { var inst_offset = instReader.ReadInt32(); // Read the relative pointer to the instrument anchor = instReader.BaseStream.Position; // store the position to jump back into. if (inst_offset > 0) // If we have a 0 offset, then the instrument is unassigned. { instReader.BaseStream.Position = BaseAddress + inst_offset; // Seek to the offset of the instrument. current_header = instReader.ReadUInt32(); // Read the 4 byte identity of the instrument. var NewINST = new Instrument(); NewINST.Keys = new InstrumentKey[0xF0]; switch (current_header) { case INST: { instReader.ReadUInt32(); // The first 4 bytes following an instrument is always 0, for some reason. Maybe reserved. NewINST.Pitch = instReader.ReadSingle(); // 4 byte float pitch NewINST.Volume = instReader.ReadSingle(); // 4 byte float volume /* Lots of skipping, i havent added these yet, but i'll comment what they are. */ var poscioffs = instReader.ReadUInt32(); // offset to first oscillator table var poscicnt = instReader.ReadUInt32(); // Offset to second oscillator count // Console.WriteLine("Oscillator at 0x{0:X}, length {1}", poscioffs, poscicnt); //Console.ReadLine(); instReader.ReadUInt32(); // Offset to first effect object instReader.ReadUInt32(); // offset to second effect object instReader.ReadUInt32(); // offset of first sensor object instReader.ReadUInt32(); // offset of second sensor object /*////////////////////////////////////////////////////////////////////////////*/ var keyCounts = instReader.ReadInt32(); // How many key regions are in here. int KeyHigh = 0; int KeyLow = 0; for (int k = 0; k < keyCounts; k++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; var keyreg_offset = instReader.ReadInt32(); // This will be where the data for our key region is. var keyptr_return = instReader.BaseStream.Position; // This is our position after reading the pointer, we'll need to return to it instReader.BaseStream.Position = BaseAddress + keyreg_offset; // Seek to the key region byte key = instReader.ReadByte(); // Read the key identifierr KeyHigh = key; // Set the highest key to what we just read. instReader.BaseStream.Seek(3, SeekOrigin.Current); // 3 bytes, unused. var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); var velreg_offs = instReader.ReadInt32(); // read the offset of the velocity region var velreg_retn = instReader.BaseStream.Position; // another one of these. Return pointer instReader.BaseStream.Position = velreg_offs + BaseAddress; int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < ((1 + VelHigh) - VelLow); idx++) // See below for what this is doing { NewKey.keys[(VelLow + idx)] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } instReader.BaseStream.Position = velreg_retn; // return to our pointer position [THIS IS BELOW] } for (int idx = 0; idx < (KeyHigh - KeyLow); idx++) // The keys are gappy. { NewINST.Keys[(KeyLow + idx)] = NewKey; // So we want to interpolate the previous keys across the empty ones, so that way it's a region NewINST.Keys[127] = NewKey; } KeyLow = KeyHigh; // Set our new lowest key to the previous highest instReader.BaseStream.Position = keyptr_return; // return to our last pointer position } break; } case PER2: { NewINST.IsPercussion = true; instReader.BaseStream.Seek(0x84, SeekOrigin.Current); // 0x88 - 4 (PERC) for (int per = 0; per < 100; per++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; var keyreg_offset = instReader.ReadInt32(); // This will be where the data for our key region is. var keyptr_return = instReader.BaseStream.Position; // This is our position after reading the pointer, we'll need to return to it if (keyreg_offset == 0) { continue; // Skip, its empty. } instReader.BaseStream.Position = BaseAddress + keyreg_offset; // seek to position. NewINST.Pitch = instReader.ReadSingle(); NewINST.Volume = instReader.ReadSingle(); instReader.BaseStream.Seek(8, SeekOrigin.Current); var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); var velreg_offs = instReader.ReadInt32(); // read the offset of the velocity region var velreg_retn = instReader.BaseStream.Position; // another one of these. Return pointer instReader.BaseStream.Position = velreg_offs + BaseAddress; int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < (VelHigh - (VelLow)); idx++) // See below for what this is doing { NewKey.keys[(VelLow + (idx))] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } instReader.BaseStream.Position = velreg_retn; // return to our pointer position [THIS IS BELOW] } instReader.BaseStream.Position = keyptr_return; NewINST.Keys[per] = NewKey; // oops, add to instrument data or else it doesnt load x.x NewINST.Keys[127] = NewKey; } break; } case PERC: break; } Instruments[inst_id] = NewINST; // Store it in the instruments bank } instReader.BaseStream.Position = anchor; // return back to our original pos to read the next pointer } }
public static uint Parse(this BeBinaryReader br, out uint b) { b = br.ReadUInt32(); return(b); }
public void LoadAAFile(string filename, JAIVersion version) { WSYS = new WaveSystem[0xFF]; // None over 256 please :). IBNK = new InstrumentBank[0xFF]; // These either. var aafdata = File.ReadAllBytes(filename); // We're just going to load a whole copy into memory because we're lame -- having this buffer in memory makes it easy to pass as a ref to stream readers later. var aafRead = new BeBinaryReader(new MemoryStream(aafdata)); bool done = false; while (!done) { var ChunkID = aafRead.ReadUInt32(); long anchor; var name = convertChunkName(ChunkID); Console.WriteLine("[AAF] Found chunk: {0}", name); switch (ChunkID) { case 0: done = true; // either we're misalligned or done, so just stopo here. break; case 1: // Don't know case 5: case 4: case 6: case 7: aafRead.ReadUInt32(); aafRead.ReadUInt32(); aafRead.ReadUInt32(); break; case 2: // INST case 3: // WSYS { while (true) { var offset = aafRead.ReadUInt32(); if (offset == 0) { break; // 0 means we reached the end. } var size = aafRead.ReadUInt32(); var type = aafRead.ReadUInt32(); anchor = aafRead.BaseStream.Position; // Store our return position. aafRead.BaseStream.Position = offset; // Seek to the offset pos. if (ChunkID == 3) { var b = new WaveSystem(); // Load the wavesystem b.LoadWSYS(aafRead); WSYS[b.id] = b; // store it Console.WriteLine("\t WSYS at 0x{0:X}", offset); } else if (ChunkID == 2) { var x = new InstrumentBank(); x.LoadInstrumentBank(aafRead, version); Console.WriteLine("\t IBNK at 0x{0:X}", offset); IBNK[x.id] = x; // Store it } aafRead.BaseStream.Position = anchor; // Return back to our original pos after loading. } break; } } } }
public static OfpWildcards Parse(this BeBinaryReader br, out OfpWildcards b) { b = new OfpWildcards(br.ReadUInt32()); return(b); }
public static void unpack(string barc, string outdir) { if (!Directory.Exists(outdir)) { Directory.CreateDirectory(outdir); } var schemastm = File.OpenWrite(outdir + "\\schema.bin"); var schemawt = new BeBinaryWriter(schemastm); var barcstm = File.OpenRead(barc); var barcread = new BeBinaryReader(barcstm); schemawt.Write((int)barcstm.Length); var bhead = barcread.ReadUInt64(); // Should be BARC. if (bhead != 0x2D2D2D2D42415243) { Console.WriteLine("!!!! BARC header didn't match! 0x{0:X}!=0x2D2D2D2D42415243", bhead); return; } barcread.ReadInt32(); // skip var count = barcread.ReadInt32(); schemawt.Write(count); var ARCFile = util.readBARCStringWE(barcread); schemawt.Write(ARCFile); var vread = File.OpenRead(ARCFile); addr_history = new bool[vread.Length * 3]; seq_map = new int[vread.Length * 3]; var names = new string[count]; for (int i = 0; i < count; i++) { var seqname = util.readBARCStringWE(barcread); var outname = string.Format("{0:D6}.bms", i); names[i] = outname + " = " + seqname; barcread.ReadUInt32(); barcread.ReadUInt32(); // Idk, but im sure as hell not using these for this app. var offset = barcread.ReadUInt32(); if (addr_history[offset]) { var bx = File.OpenWrite(outdir + "\\" + outname); var bxw = new BeBinaryWriter(bx); bxw.Write(0xAFBFCFDF); bxw.Write(seq_map[offset]); barcread.ReadUInt32(); // just to keep aligned. Console.WriteLine("Alias."); continue; } addr_history[offset] = true; seq_map[offset] = i; var size = barcread.ReadUInt32(); var filedata = new byte[size]; vread.Position = offset; vread.Read(filedata, 0, (int)size); File.WriteAllBytes(outdir + "\\" + outname, filedata); } File.WriteAllLines(outdir + "\\names.txt", names); schemawt.Close(); schemastm.Close(); }
/// <summary> /// 从流中读一个UInt32生成通配符 /// </summary> /// <param name="stream"></param> public OfpWildcards(Stream stream) { BeBinaryReader br = new BeBinaryReader(stream, Encoding.ASCII, true); _value = br.ReadUInt32(); }
public static OfpActionCapabilities Parse(this BeBinaryReader br, out OfpActionCapabilities b) { b = (OfpActionCapabilities)br.ReadUInt32(); return(b); }
private int back = 0; // utility public void LoadWSYS(BeBinaryReader WSYSReader) { BaseAddress = WSYSReader.BaseStream.Position; waves = new WSYSWave[32768]; // TEMPORARY. Fix WSYS Loading! current_header = WSYSReader.ReadInt32(); if (current_header != WSYS) { Console.WriteLine("Error: Section base at {0} is not WSYS, is instead {1:X}", BaseAddress, current_header); return; } size = WSYSReader.ReadInt32(); id = WSYSReader.ReadInt32(); WSYSReader.ReadUInt32(); // 4 bytes, not used. .. I think // A little messy, but both of these need to be loaded before we can continue. var winfo_offset = WSYSReader.ReadInt32(); // relative offset to wave info offset pointer table. var wbct_offset = WSYSReader.ReadInt32(); // relative offset to wave info offset pointer table. int[] winfOffsets; int[] wbctOffsets; { // Load WINF offsets. WSYSReader.BaseStream.Position = BaseAddress + winfo_offset; current_header = WSYSReader.ReadInt32(); // Should be WINF winfOffsets = new int[WSYSReader.ReadInt32()]; // 4 bytes count for (int i = 0; i < winfOffsets.Length; i++) { winfOffsets[i] = WSYSReader.ReadInt32(); // Int32's following the length. } // Load WBCT data WSYSReader.BaseStream.Position = BaseAddress + wbct_offset; current_header = WSYSReader.ReadInt32(); // Should be WBCT WSYSReader.ReadUInt32(); // 4 bytes unused? wbctOffsets = new int[WSYSReader.ReadInt32()]; // 4 bytes count for (int i = 0; i < wbctOffsets.Length; i++) { wbctOffsets[i] = WSYSReader.ReadInt32(); // Int32's following the length. } } groups = new WSYSGroup[winfOffsets.Length]; for (int i = 0; i < winfOffsets.Length; i++) { /* This is loading the data for a WINF */ WSYSReader.BaseStream.Position = BaseAddress + winfOffsets[i]; var Group = new WSYSGroup(); Group.path = Helpers.readArchiveName(WSYSReader); var fobj = File.OpenRead("./Banks/" + Group.path); // Open the .AW file (AW contains only ADPCM data, nothing else.) var fobj_reader = new BeBinaryReader(fobj); // Create a reader for it. int waveInfoCounts = WSYSReader.ReadInt32(); // 4 byte count int[] info_offsets = new int[waveInfoCounts]; for (int q = 0; q < waveInfoCounts; q++) { info_offsets[q] = WSYSReader.ReadInt32(); } Group.IDMap = new int[UInt16.MaxValue]; // We have to initialize the containers for the wave information Group.Waves = new WSYSWave[waveInfoCounts]; /* Since the count should be equal, we're loading the info for the WBCT in he re as well */ WSYSReader.BaseStream.Position = BaseAddress + wbctOffsets[i]; // The first several bytes of the WBCT are uselss, a WBCT points directly to a SCNE. current_header = WSYSReader.ReadInt32(); // This should be SCNE. WSYSReader.ReadUInt64(); // The next 8 bytes are useless. var cdf_offset = WSYSReader.ReadInt32(); // However, the next 4 contain the pointer to c_DF relative to our base. WSYSReader.BaseStream.Position = BaseAddress + cdf_offset; current_header = WSYSReader.ReadInt32(); // Should be C_DF. int waveid_count = WSYSReader.ReadInt32(); // Count of our WAVE ID int[] waveid_offsets = new int[waveid_count]; // Be ready to store them for (int q = 0; q < waveid_count; q++) { waveid_offsets[q] = WSYSReader.ReadInt32(); // Read each waveid } // Finally, we're going to get our wave data. for (int wav = 0; wav < waveInfoCounts; wav++) { var o_Wave = new WSYSWave(); WSYSReader.BaseStream.Position = BaseAddress + waveid_offsets[wav]; var aw_id = WSYSReader.ReadInt16(); // Strangely enough, it has an AW_ID here. This tells which file it sits in? I guess they're normally loaded separately. o_Wave.id = WSYSReader.ReadInt16(); // This is the waveid for this wave, it's normally globally unique, but some games hot-load banks. WSYSReader.BaseStream.Position = BaseAddress + info_offsets[wav]; // Seek to the offset of the actual wave parameters. WSYSReader.ReadByte(); // I have no clue what the first byte does. o_Wave.format = WSYSReader.ReadByte(); // Tells what format it's in, usually type 5 AFC (ADPCM) o_Wave.key = WSYSReader.ReadByte(); // Tells the base key for this wave (0-127 usually) WSYSReader.ReadByte(); // I have no clue what this byte does. //var srate = WSYSReader.ReadBytes(4); o_Wave.sampleRate = WSYSReader.ReadSingle(); /* * oh. its a float. * oops * if (o_Wave.format == 5) * { * o_Wave.sampleRate = 32000; /// ???? * } * * if (o_Wave.sampleRate == 5666) // What the actual f**k. Broken value, can't figure out why. * { * o_Wave.sampleRate = 44100; // I guess set the srate to 44100? * } */ o_Wave.w_start = WSYSReader.ReadUInt32(); // 4 byte start in AW o_Wave.w_size = WSYSReader.ReadUInt32(); // 4 byte size in AW var b = WSYSReader.ReadUInt32(); o_Wave.loop = b == UInt32.MaxValue ? true : false; // Weird looping flag? o_Wave.loop_start = (int)Math.Floor(((WSYSReader.ReadInt32() / 8f)) * 16f); o_Wave.loop_end = (int)Math.Floor(((WSYSReader.ReadInt32() / 8f)) * 16f); o_Wave.sampleCount = WSYSReader.ReadInt32(); // 4 byte sample cont // Console.WriteLine("L {0:X} (0x{1:X}), LS {2:X} , LE {3:X}, SC {4:X} SZ {5:X}", o_Wave.loop, b, o_Wave.loop_start, o_Wave.loop_end,o_Wave.sampleCount,o_Wave.w_size); //Console.ReadLine(); var name = string.Format("0x{0:X}.wav", o_Wave.id); var name2 = string.Format("0x{0:X}.par", o_Wave.id); if (!Directory.Exists("./WSYS_CACHE")) { Directory.CreateDirectory("./WSYS_CACHE"); } if (!Directory.Exists("./WSYS_CACHE/AW_" + Group.path)) { Directory.CreateDirectory("./WSYS_CACHE/AW_" + Group.path); } o_Wave.pcmpath = "./WSYS_CACHE/AW_" + Group.path + "/" + name; Group.Waves[wav] = o_Wave; // We're done with just about everything except the PCM data now (ADPCM / AFC conversion) Group.IDMap[o_Wave.id] = wav; waves[o_Wave.id] = o_Wave; // TEMPORARY, FIX WSYS LOADING! fobj_reader.BaseStream.Position = o_Wave.w_start; var adpcm = fobj_reader.ReadBytes((int)o_Wave.w_size); if (!File.Exists(o_Wave.pcmpath)) { Helpers.AFCtoPCM16(adpcm, o_Wave.sampleRate, (int)o_Wave.w_size, o_Wave.format, o_Wave.pcmpath); } } } }
/* * JAIV1 INST Structure * 0x00 int32 0x494E5354 'INST' * 0x04 int32 0 - unused? * 0x08 float frequencyMultiplier * 0x0C float gainMultiplier * 0x10 int32 oscillator table offset * 0x14 int32 oscillator table count * 0x18 int32 effect table offset * 0x1C int32 effect table size * 0x20 int32 sensor object table * 0x24 int32 sensor object table count * 0x28 int32 key_region_count * 0x2C *KeyRegion[key_region_count] * */ public JInstrument loadInstrument(BeBinaryReader binStream, int Base) { var Inst = new JInstrument(); if (binStream.ReadUInt32() != INST) // Check if first 4 bytes are INST { throw new InvalidDataException("Data is not an INST"); } binStream.ReadUInt32(); // oh god oh god oh god its null Inst.Pitch = binStream.ReadSingle(); Inst.Volume = binStream.ReadSingle(); var osc1Offset = binStream.ReadUInt32(); var osc2Offset = binStream.ReadUInt32(); binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // // * trashy furry screaming * // int keyregCount = binStream.ReadInt32(); // Read number of key regions JInstrumentKey[] keys = new JInstrumentKey[0x81]; // Always go for one more. int[] keyRegionPointers = new int[keyregCount]; keyRegionPointers = Helpers.readInt32Array(binStream, keyregCount); var keyLow = 0; // For region spanning. for (int i = 0; i < keyregCount; i++) // Loop through all pointers. { binStream.BaseStream.Position = keyRegionPointers[i] + Base; // Set position to key pointer pos (relative to base) var bkey = readKeyRegion(binStream, Base); // Read the key region for (int b = 0; b < bkey.baseKey - keyLow; b++) { // They're key regions, so we're going to have a toothy / gappy piano. So we need to span the missing gaps with the previous region config. // This means that if the last key was 4, and the next key was 8 -- whatever parameters 4 had will span keys 4 5 6 and 7. keys[b + keyLow] = bkey; // span the keys keys[127] = bkey; } keyLow = bkey.baseKey; // Store our last key } Inst.Keys = keys; byte oscCount = 0; if (osc1Offset > 0) { oscCount++; } if (osc2Offset > 0) { oscCount++; } Inst.oscillatorCount = oscCount; // Redundant? Inst.oscillators = new JOscillator[oscCount]; // new oscillator array if (osc1Offset != 0) // if the oscillator isnt null { binStream.BaseStream.Position = osc1Offset + Base; // seek to it's position Inst.oscillators[0] = loadOscillator(binStream, Base); // then load it. } if (osc2Offset != 0) // if the second oscillator isn't null { binStream.BaseStream.Position = osc2Offset + Base; // seek to its position Inst.oscillators[1] = loadOscillator(binStream, Base); // and load it. } return(Inst); }
public static OfpPortConfig Parse(this BeBinaryReader br, out OfpPortConfig b) { b = (OfpPortConfig)br.ReadUInt32(); return(b); }
public void LoadBAAFile(string filename, JAIVersion version) { WSYS = new WaveSystem[0xFF]; // None over 256 please :). IBNK = new InstrumentBank[0xFF]; // These either. var aafdata = File.ReadAllBytes(filename); // We're just going to load a whole copy into memory because we're lame -- having this buffer in memory makes it easy to pass as a ref to stream readers later. var aafRead = new BeBinaryReader(new MemoryStream(aafdata)); bool done = false; while (!done) { var ChunkID = aafRead.ReadUInt32(); long anchor; var name = convertChunkName(ChunkID); Console.WriteLine("[BAA] Found chunk: {0}", name); switch (ChunkID) { case 1046430017: // >_AA done = true; // either we're misalligned or done, so just stopo here. break; case 1094803260: // AA_< break; case 1651733536: // BST { var offset_sta = aafRead.ReadUInt32(); var offset_end = aafRead.ReadUInt32(); break; } case 1651733614: // BSTN { var offset_sta = aafRead.ReadUInt32(); var offset_end = aafRead.ReadUInt32(); break; } case 1651729184: // BSC { var offset_sta = aafRead.ReadUInt32(); var offset_end = aafRead.ReadUInt32(); break; } case 1651403552: // BNK { var id = aafRead.ReadUInt32(); var offset = aafRead.ReadUInt32(); anchor = aafRead.BaseStream.Position; // Store our return position. aafRead.BaseStream.Position = offset; // Seek to the offset pos. var b = new InstrumentBank(); b.LoadInstrumentBank(aafRead, version); // Load it up IBNK[id] = b; aafRead.BaseStream.Position = anchor; // Return back to our original pos after loading. break; } case 2004033568: // WSYS { var id = aafRead.ReadUInt32(); var offset = aafRead.ReadUInt32(); var flags = aafRead.ReadUInt32(); anchor = aafRead.BaseStream.Position; // Store our return position. aafRead.BaseStream.Position = offset; // Seek to the offset pos. var b = new WaveSystem(); b.LoadWSYS(aafRead); WSYS[id] = b; aafRead.BaseStream.Position = anchor; // Return back to our original pos after loading. break; } } } }
public static void Repack(string dir, string xgr) { string imgb = Path.Combine(Path.GetDirectoryName(xgr), $"{Path.GetFileNameWithoutExtension(xgr)}.imgb"); if (!File.Exists(imgb)) { throw new Exception("IMGB file not found."); } FileStream stream = File.Open(xgr, FileMode.Open, FileAccess.ReadWrite); FileStream imgbStream = File.Open(imgb, FileMode.Open, FileAccess.ReadWrite); BeBinaryReader reader = new BeBinaryReader(stream); BinaryWriter xgrWriter = new BinaryWriter(stream); BinaryWriter imgbWriter = new BinaryWriter(imgbStream); if (reader.ReadInt32() == 0x57504400) { uint fileCount = reader.ReadUInt32(); reader.BaseStream.Position += 8; //zeroes for (int i = 0; i < fileCount; i++) { string fileName = Encoding.ASCII.GetString(reader.ReadBytes(16)).Replace($"{(char)0}", string.Empty); uint infoOffset = reader.ReadUInt32(); uint infoSize = reader.ReadUInt32(); string fileExt = Encoding.ASCII.GetString(reader.ReadBytes(8)).Replace($"{(char)0}", string.Empty); string filePath = Path.Combine(dir, $"{fileName}.{fileExt}"); if (!File.Exists($"{filePath}.dds") && !File.Exists(filePath)) { continue; } long current = reader.BaseStream.Position; reader.BaseStream.Position = infoOffset; if (fileExt == "txbh") { byte[] bytes = File.ReadAllBytes($"{filePath}.dds").Skip(128).ToArray(); reader.BaseStream.Position += 88; uint offsetImgb = reader.ReadUInt32(); uint size = reader.ReadUInt32(); if (bytes.Length != size) { throw new Exception("The new file size should be the same as the original file size."); } imgbWriter.BaseStream.Position = offsetImgb; imgbWriter.Write(bytes); } else { byte[] bytes = File.ReadAllBytes(filePath); if (bytes.Length != infoSize) { throw new Exception("The new file size should be the same as the original file size."); } xgrWriter.BaseStream.Position = infoOffset; xgrWriter.Write(bytes); } Console.WriteLine($"Repacked: {fileName}.{fileExt}"); reader.BaseStream.Position = current; } } else { throw new Exception("File is not a XGR file."); } reader.Close(); xgrWriter.Close(); stream.Close(); imgbWriter.Close(); imgbStream.Close(); }
public static OfpFlowWildcards Parse(this BeBinaryReader br, out OfpFlowWildcards b) { b = (OfpFlowWildcards)br.ReadUInt32(); return(b); }
public static void packBARC(string dir, string barcname) { var barcstm = File.OpenWrite(barcname); var barcwrite = new BeBinaryWriter(barcstm); barcwrite.Write(0x424152432D2D2D2DL); // BARC---- barcwrite.Write((uint)0xDEADBEEF); // skip var schema = File.OpenRead(dir + "\\schema.bin"); var schemard = new BeBinaryReader(schema); var total_off = 0; var end_size = schemard.ReadInt32(); var count = schemard.ReadInt32(); var seqArcFile = schemard.ReadString(); barcwrite.Write(count); var sqarc_out = File.OpenWrite(dir + "\\" + seqArcFile); util.writeBARCString(barcwrite, seqArcFile); seq_map = new int[0xFFFFF]; TrackSizes = new int[0xFFFFF]; for (int i = 0; i < count; i++) { var inname = string.Format("{0:D6}.bms", i); var e = File.ReadAllBytes(dir + "\\" + inname); var wx = File.OpenRead(dir + "\\" + inname); var wxr = new BeBinaryReader(wx); var alias = wxr.ReadUInt32(); bool doAli = false; int sIdx = 0; if (alias == 0xAFBFCFDF) { sIdx = wxr.ReadInt32(); doAli = true; Console.WriteLine("Aliased {0}", sIdx); } wx.Close(); util.writeBARCString(barcwrite, inname); barcwrite.Write((int)2); barcwrite.Write((int)3); if (doAli) { Console.WriteLine("Alias map to {0:X}, {1}", seq_map[sIdx], sIdx); barcwrite.Write(seq_map[sIdx]); barcwrite.Write(TrackSizes[sIdx]); continue; } else { barcwrite.Write(total_off); } Console.WriteLine("Sequence {0} at {1:X}", i, total_off); seq_map[i] = total_off; TrackSizes[i] = e.Length; barcwrite.Write(e.Length); if (doAli) { continue; } sqarc_out.Position = total_off; sqarc_out.Write(e, 0, e.Length); var Pad = new byte[0x20]; sqarc_out.Write(Pad, 0, Pad.Length); total_off += e.Length + Pad.Length; } barcwrite.Flush(); sqarc_out.Flush(); }
public static void Unpack(string xgr, string dir) { string imgb = Path.Combine(Path.GetDirectoryName(xgr), $"{Path.GetFileNameWithoutExtension(xgr)}.imgb"); if (!File.Exists(imgb)) { throw new Exception("IMGB file not found."); } FileStream stream = File.OpenRead(xgr); FileStream imgbStream = File.OpenRead(imgb); BeBinaryReader reader = new BeBinaryReader(stream); BinaryReader imgbReader = new BinaryReader(imgbStream); if (reader.ReadInt32() == 0x57504400) { uint fileCount = reader.ReadUInt32(); reader.BaseStream.Position += 8; //zeroes for (int i = 0; i < fileCount; i++) { string fileName = Encoding.ASCII.GetString(reader.ReadBytes(16)).Replace($"{(char)0}", string.Empty); uint infoOffset = reader.ReadUInt32(); uint infoSize = reader.ReadUInt32(); string fileExt = Encoding.ASCII.GetString(reader.ReadBytes(8)).Replace($"{(char)0}", string.Empty); string filePath = Path.Combine(dir, $"{fileName}.{fileExt}"); long current = reader.BaseStream.Position; reader.BaseStream.Position = infoOffset; if (fileExt == "txbh") { string magicWord = Encoding.ASCII.GetString(reader.ReadBytes(8)).Replace($"{(char)0}", string.Empty); reader.BaseStream.Position += 56; //unknow string fileType = Encoding.ASCII.GetString(reader.ReadBytes(4)).Replace($"{(char)0}", string.Empty); reader.BaseStream.Position += 2; //unknow GTEXFormat.GtexPixelFormat format = (GTEXFormat.GtexPixelFormat)reader.ReadByte(); byte mimapCount = reader.ReadByte(); reader.ReadByte(); //unknow bool isCubeMap = reader.ReadBoolean(); ushort width = reader.ReadUInt16(); ushort height = reader.ReadUInt16(); short depth = reader.ReadInt16(); int linerSize = reader.ReadInt32(); reader.BaseStream.Position += 4; uint offsetImgb = reader.ReadUInt32(); uint size = reader.ReadUInt32(); imgbReader.BaseStream.Position = offsetImgb; byte[] raw = imgbReader.ReadBytes((int)size); byte[] result = DDS.Create(width, height, format, mimapCount, depth, linerSize, raw); File.WriteAllBytes($"{filePath}.dds", result); } else { byte[] bytes = reader.ReadBytes((int)infoSize); File.WriteAllBytes($"{filePath}.{fileExt}", bytes); } Console.WriteLine($"Unpacked: {fileName}.{fileExt}"); reader.BaseStream.Position = current; } } else { throw new Exception("File is not a XGR file."); } reader.Close(); stream.Close(); imgbReader.Close(); imgbStream.Close(); }