public static void AnalyzeChunkSubBuffer(int currentBlock, int startPos, byte[] data, ChunkAnalysisResult chunkAnalysisResult) { var intBuffer = new byte[4]; var allHigh = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }; using (var ms2 = new MemoryStream(data)) { Console.WriteLine(); Console.WriteLine($"Info for block #{currentBlock} starting at {startPos} length {data.Length} end {startPos+data.Length}"); Console.WriteLine($"-------------------------------"); var blockMagic = new byte[4]; ms2.Read(blockMagic, 0, 4); chunkAnalysisResult.BlockMagic = blockMagic; Console.WriteLine($"Guessed block magic: {StringUtils.ByteArrayToHexString(blockMagic)}"); ms2.Read(intBuffer, 0, 4); var pluginNameLength = BigEndian.ToInt32(intBuffer, 0); if (pluginNameLength < ms2.Length - ms2.Position) { var pluginNameBuf = new byte[pluginNameLength]; ms2.Read(pluginNameBuf, 0, pluginNameLength); if (chunkAnalysisResult.PluginName == "") { chunkAnalysisResult.PluginName = Encoding.BigEndianUnicode.GetString(pluginNameBuf); } Console.WriteLine($"Guessed plugin name: {Encoding.BigEndianUnicode.GetString(pluginNameBuf)}"); } else { ms2.Seek(-4, SeekOrigin.End); var buf3 = new byte[4]; ms2.Read(buf3, 0, 4); if (buf3.SequenceEqual(allHigh)) { chunkAnalysisResult.EndChunk = ms2.ToByteArray(); Console.WriteLine("Probably the page stuff (end chunk?)"); } else { ms2.Seek(0, SeekOrigin.Begin); var presetBuf = new byte[data.Length]; ms2.Read(presetBuf, 0, data.Length); chunkAnalysisResult.HasPresetNameAtEnd = true; Console.WriteLine($"Probably the current preset name? Decoded: {Encoding.ASCII.GetString(presetBuf)}"); } return; } var buf2 = new byte[4]; ms2.Read(buf2, 0, 4); var empty = new byte[] { 0x00, 0x00, 0x00, 0x00 }; if (buf2.SequenceEqual(empty)) { Console.WriteLine("Got 4x 0x00 after the plugin name"); } else { Console.WriteLine("Did NOT get 4x 0x00 after the plugin name"); } ms2.Read(intBuffer, 0, 4); if (intBuffer.SequenceEqual(allHigh)) { ms2.Read(intBuffer, 0, 4); if (intBuffer.SequenceEqual(Tfx.DEADBEEF)) { Console.WriteLine("Empty block without data"); } else { var midiBlockLength = BigEndian.ToInt32(intBuffer, 0); if (ms2.Position + midiBlockLength + 4 == ms2.Length) { chunkAnalysisResult.HasMidi = true; if (midiBlockLength == 4) { chunkAnalysisResult.HasEmptyMidi = true; } Console.WriteLine("Is probably a midi buffer"); } else { Console.WriteLine("Unknown block?"); } } } else { var subBlockLength = BigEndian.ToInt32(intBuffer, 0); if (ms2.Length - ms2.Position - 4 == subBlockLength) { Console.WriteLine($"Sub block length matches length {subBlockLength}"); } else { Console.WriteLine("Sub block length does NOT match length"); } } var buf = new byte[4]; ms2.Seek(-4, SeekOrigin.End); ms2.Read(buf, 0, 4); if (buf.SequenceEqual(Tfx.DEADBEEF)) { Console.WriteLine("Ends with DEADBEEF"); } else { Console.WriteLine("Does not end with DEADBEEF"); } } }
public static ChunkAnalysisResult AnalyzeChunk(byte[] data, string file) { var chunkAnalysisResult = new ChunkAnalysisResult(); var intBuffer = new byte[4]; Console.WriteLine($"Chunk Info for {file}"); Console.WriteLine( "======================================================================================================="); Console.WriteLine(""); using (var ms = new MemoryStream(data)) { ms.Read(intBuffer, 0, 4); var totalLength = LittleEndian.ToInt32(intBuffer, 0); var lengthDifference = ms.Length - totalLength - 16; Console.WriteLine( $"Content total length: {totalLength} (length difference: {lengthDifference}, should be 0)"); ms.Seek(12, SeekOrigin.Current); ms.Read(intBuffer, 0, 4); var numParameters = LittleEndian.ToInt32(intBuffer, 0); Console.WriteLine($"Num parameters: {numParameters}"); chunkAnalysisResult.NumParameters = numParameters; ms.Seek(numParameters * 4, SeekOrigin.Current); var currentBlock = 0; while (true) { currentBlock++; if (ms.Position == ms.Length) { break; } ms.Read(intBuffer, 0, 4); var blockLength = LittleEndian.ToInt32(intBuffer, 0); var startPos = ms.Position; if (ms.Position + blockLength > ms.Length) { Console.WriteLine( $"Error reading block starting at {ms.Position - 4}: Block length exceeds file size"); break; } if (blockLength == 0) { var unknownBlockStart = ms.Position; ms.Read(intBuffer, 0, 4); var subBlockLength = LittleEndian.ToInt32(intBuffer, 0); var blockBuffer = new byte[subBlockLength]; if (subBlockLength == 0) { Console.WriteLine(); Console.WriteLine($"Info for block #{currentBlock} starting at {unknownBlockStart} length {subBlockLength} end {unknownBlockStart+subBlockLength}"); Console.WriteLine($"-------------------------------"); Console.WriteLine("Empty unknown data block"); continue; } ms.Seek(-4, SeekOrigin.Current); ms.Read(blockBuffer, 0, subBlockLength); Console.WriteLine(); Console.WriteLine($"Info for block #{currentBlock} starting at {unknownBlockStart} length {subBlockLength} end {unknownBlockStart+subBlockLength}"); Console.WriteLine($"-------------------------------"); Console.WriteLine("Unknown data block"); } else { var blockBuffer = new byte[blockLength]; ms.Read(blockBuffer, 0, blockLength); AnalyzeChunkSubBuffer(currentBlock, (int)startPos, blockBuffer, chunkAnalysisResult); } } } return(chunkAnalysisResult); }