public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(4); if (data.Length < 4) { return(null); } if (data[0x00] != 0x57) { return(null); } if (data[0x01] != 0x42) { return(null); } if (data[0x02] != 0x4E) { return(null); } if (data[0x03] != 0x44) { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(0x4); if (data[0x0000] == 0x00 && data[0x0001] == 0x00) { return(null); } if ((data[0x0000] & 0x1F) != 0) { return(null); } if (data[0x0001] >= 0x20) { return(null); } if (data[0x0002] != 0x00) { return(null); } if (data[0x0003] != 0x38) { return(null); } reader.Skip(0x1FFC); var data2 = reader.Read(0x4); if (data2[0x0000] == 0x00 && data2[0x0001] == 0x00) { return(null); } if ((data2[0x0000] & 0x1F) != 0) { return(null); } if (data2[0x0001] >= 0x20) { return(null); } if (data2[0x0002] != 0x00) { return(null); } if (data2[0x0003] != 0x38) { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(8); if (data.Length < 8) { return(null); } if (data[0] != 0x10) { return(null); } if (data[1] != 0x00) { return(null); } if (data[2] != 0x00) { return(null); } if (data[3] != 0x00) { return(null); } switch (data[4]) { case 0x00: break; case 0x01: break; case 0x02: break; case 0x08: break; case 0x09: break; default: return(null); } if (data[5] != 0x00) { return(null); } if (data[6] != 0x00) { return(null); } if (data[7] != 0x00) { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(0x10); if (data.Length < 0x10) { return(null); } var length = Bitter.ToInt32S(data); if (length == 0) { return(null); } if ((length & 0x7FF) != 0) { return(null); } if (data[0x05] == 0) { return(null); } var sampleRate = Bitter.ToInt16S(data, 6); if (sampleRate == 0) { return(null); } if (data[0x08] == 0) { return(null); } if (data[0x08] > 2) { return(null); } return(new VagHeuristicResult(this) { Start = 0x800, Interleave = 0x800, Channels = data[0x08], SampleRate = sampleRate, Length = length }); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(8); if (data.Length < 8) { return(null); } if (Encodings.CP437.GetString(data.Slice(0, 8)) != "PS-X EXE") { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { if (reader.Length < 0x804) { return(null); } var data = reader.Read(0x2C); if (Bitter.ToInt32(data.Slice(0x00)) != 0x08640001) { return(null); } if (Bitter.ToInt32(data.Slice(0x04)) != 0) { return(null); } var startOffset = Bitter.ToInt32(data.Slice(0x08)); if (startOffset < 0x00000030) { return(null); } var result = new VagHeuristicResult(this) { Start = startOffset, Length = Bitter.ToInt32(data.Slice(0x0C)), LoopStart = Bitter.ToInt32(data.Slice(0x10)), LoopEnd = Bitter.ToInt32(data.Slice(0x14)), SampleRate = Bitter.ToInt32(data.Slice(0x18)), Channels = Bitter.ToInt32(data.Slice(0x1C)), Interleave = Bitter.ToInt32(data.Slice(0x24)), Volume = new BigRational(Bitter.ToInt32(data.Slice(0x28)), 100), }; if (data[0x20] != 0x00 || data[0x21] != 0x00 || data[0x22] != 0x00 || data[0x23] != 0x00) { result.Key = data.Slice(0x20, 4).ToArray(); } return(result); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(0x10); if (data.Length < 0x10) { return(null); } var a = Bitter.ToInt32(data); var b = Bitter.ToInt32(data, 4); var c = Bitter.ToInt32(data, 8); var d = Bitter.ToInt32(data, 12); if (a <= 0) { return(null); } if (b <= 0) { return(null); } if (c < 0) { return(null); } if (d != 0) { return(null); } if (a - b - c != 16384) { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var maxTable = int.MaxValue; var offsets = new List <int>(); for (var i = 0; i < maxTable; i++) { var offset = reader.ReadInt(); if (offset >= 4 && offset < 0x1000000 && !offsets.Contains(offset)) { offsets.Add(offset); if (maxTable > offset / 4) { maxTable = offset / 4; } } else if (offset != 0 && offset < i * 4) { return(null); } } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(12); if (data.Length < 12) { return(null); } if (data[0] % 4 != 0) { return(null); } if (data[0] == 0 && data[1] == 0) { return(null); } if (data[2] != 0) { return(null); } if (data[3] != 0) { return(null); } if (data[4] != 1) { return(null); } if (data[5] != 0) { return(null); } if (data[6] == 0 && data[7] == 0) { return(null); } if (data[8] == 0 && data[9] == 0) { return(null); } if (data[10] != 0) { return(null); } if (data[11] != 0) { return(null); } return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { // Must have at least 4 bytes if (reader.Length == null || reader.Length < 4) { return(null); } // Put a hard cap of 64k as a sanity check if (reader.Length > 65536) { return(null); } // Must be divisible by 4 if ((reader.Length & 0x3) != 0) { return(null); } var data = reader.Read((int)reader.Length); // Make sure each chunk length makes sense var thisOffset = 0; while (thisOffset < reader.Length) { var thisChunkLength = Bitter.ToInt32(data, thisOffset); if (thisChunkLength == 0) { break; } if (thisChunkLength < 0) { return(null); } if (thisOffset + thisChunkLength >= reader.Length) { return(null); } if ((thisOffset & 0x3) != 0) { return(null); } thisOffset += thisChunkLength; } // Try to make sense of the timing chunk length var timingChunkLength = Bitter.ToInt32(data); if (timingChunkLength < 20) { return(null); } if (timingChunkLength >= reader.Length) { return(null); } if ((timingChunkLength & 0x3) != 0) { return(null); } // Check both the measure and the second offset, make sure they are increasing var timingMeasure = int.MinValue; var timingSector = int.MinValue; for (var i = 1; i < timingChunkLength >> 2; i += 2) { var thisTimingMeasure = Bitter.ToInt32(data, i << 2); var thisTimingSector = Bitter.ToInt32(data, 0x4 + (i << 2)); if (thisTimingMeasure < timingMeasure) { return(null); } if (thisTimingSector < timingSector) { return(null); } timingMeasure = thisTimingMeasure; timingSector = thisTimingSector; } // No reason to believe this isn't a step1 at this point return(new HeuristicResult(this)); }
public HeuristicResult Match(IHeuristicReader reader) { var data = reader.Read(0x1C); var words = MemoryMarshal.Cast <byte, int>(data); // "Svag" if (words[0] != 0x67617653) { return(null); } // Make sure length is 16-byte aligned if ((words[1] & 0xF) != 0) { return(null); } // Make sure sample rate fits in 16bits if (words[2] > 0xFFFF || words[2] <= 0) { return(null); } // More than 4 channels is pretty unlikely if (words[3] < 1 || words[3] > 4) { return(null); } // Total length must be at least the header size if (words[1] < 0x800) { return(null); } // Interleave must be non negative if (words[4] < 0) { return(null); } // Interleave must be present if more than 1 channel if (words[3] > 1 && words[4] == 0) { return(null); } // Must have at least 1 full block present if (words[1] < words[3] * words[4]) { return(null); } // The usable header length is 0x1C but the last two words are loop info, we don't care about it return(new VagHeuristicResult(this) { Start = 0x800, Length = words[1] - 0x800, SampleRate = words[2], Channels = words[3], Interleave = words[4], LoopStart = words[5], LoopEnd = words[6] }); }
public HeuristicResult Match(IHeuristicReader reader) { var noteCountMode = true; var hasBpm = false; var hasEnd = false; var hasTerminator = false; var evData = new byte[4]; while (true) { if (reader.Read(evData, 0, 4) < 4) { break; } var eventOffset = Bitter.ToInt16S(evData); var eventValue = evData[2]; var eventCommand = evData[3]; var eventParameter = eventCommand >> 4; var eventType = eventCommand & 0xF; // empty event = invalid if (Bitter.ToInt32(evData) == 0) { return(null); } // positive event offsets only if (eventOffset < 0) { return(null); } // offsets can't be present during note count if (noteCountMode && eventOffset != 0) { return(null); } // disable note count info if another event type shows up if (eventCommand != 0x00 && eventCommand != 0x01) { noteCountMode = false; } // skip the rest of processing if in note count mode if (noteCountMode) { continue; } // terminator bytes if (eventOffset == 0x7FFF) { hasTerminator = true; break; } // make sure we have the bare minimums if (eventType == 6) { hasEnd = true; } else if (eventType == 4 && eventValue + (eventParameter << 8) != 0) { hasBpm = true; } } if (!(hasBpm && hasEnd && hasTerminator)) { return(null); } return(new HeuristicResult(this)); }