public CMM(byte[] data) { for (int lineskip = 0; lineskip < data.Length; lineskip += 8) { if (ByteUtilities.ByteArrayEquals(data, lineskip, new byte[] { 0x16, 0x1A, 0x47, 0xE8, 0, 0, 0 }, 0, 7)) { int byteCount = data[lineskip + 7]; TracklistModifier = data.Skip(lineskip + 8).Take(byteCount).ToArray(); } } Map = new Dictionary <int, IEnumerable <Song> >(); for (int lineskip = 0; lineskip < data.Length; lineskip += 8) { if (data[lineskip] == 0x00 && data[lineskip + 1] == 0x53 && data[lineskip + 2] == 0xCE) { int tracklistIndex = data[lineskip + 3] - 0xA0; int tracks = data[lineskip + 7]; foreach (Stage stage in GetStageByIdInTracklist(tracklistIndex)) { IEnumerable <Song> songs = ReadSongs(data, lineskip + 16, tracks); if (Map.TryGetValue(stage.ID, out IEnumerable <Song> existing)) { Console.Error.WriteLine( $"Replacing already read {existing.Count()}-song tracklist for {stage} with newly read {songs.Count()}-song tracklist"); } Map[stage.ID] = songs; } } } }
public StageDependentSongLoader(byte[] data) { SongsByStage = new Dictionary <byte, Song>(); for (int line = 0; line < data.Length; line += 8) { if (ByteUtilities.ByteArrayEquals(data, line, SDSL_HEADER, 0, SDSL_HEADER.Length)) { byte stageID = data[line + 7]; byte songID1 = data[line + 22]; byte songID2 = data[line + 23]; ushort songID = (ushort)(0x100 * songID1 + songID2); Song s = (from g in SongIDMap.Songs where g.ID == songID select g).First(); if (SongsByStage.ContainsKey(stageID)) { Console.WriteLine(String.Format("WARNING: code mapping stage {0} to song {1} will not " + "take effect, since a later code maps it to song {2}", stageID, SongsByStage[stageID], s)); SongsByStage.Remove(stageID); } SongsByStage.Add(stageID, s); line += 24; } } }
public StageDependentSongLoader(byte[] data) { songReplacements = new List <SongReplacement>(); for (int line = 0; line < data.Length; line += 8) { if (ByteUtilities.ByteArrayEquals(data, line, SDSL_HEADER, 0, SDSL_HEADER.Length)) { byte stageID = data[line + 0x7]; ushort?songIDIn = null; ushort songIDOut; if (ByteUtilities.ByteArrayEquals(data, line + 8, SONG_ID_CONDITION, 0, SONG_ID_CONDITION.Length)) { songIDIn = (ushort)(0x100 * data[line + 14] + data[line + 15]); songIDOut = (ushort)(0x100 * data[line + 30] + data[line + 31]); } else { songIDOut = (ushort)(0x100 * data[line + 22] + data[line + 23]); } Song s = (from g in SongIDMap.Songs where g.ID == songIDOut select g).FirstOrDefault(); if (s != null) { songReplacements.Add(new SongReplacement { stageID = stageID, songID = songIDIn, song = s }); line += 24; } else { Console.WriteLine("Unknown song ID " + songIDOut.ToString("X4") + " - not currently supported."); } } } }
public TracklistModifier(byte[] data) { Dictionary <byte, byte> map1 = new Dictionary <byte, byte>(); Dictionary <byte, byte> map2 = new Dictionary <byte, byte>(); using (MemoryStream ms = new MemoryStream(data)) { byte[] line = new byte[8]; while (true) { int read = ms.Read(line, 0, 8); if (read < 8) { break; } if (ByteUtilities.ByteArrayEquals(line, 0, HEADER, 0, 7)) { int lines = line[7]; for (int i = 0; i < lines; i++) { read = ms.Read(line, 0, 8); if (read < 8) { throw new FormatException($"Could not read all of Tracklist Modifier code (line {i + 1}, read {read} bytes)"); } switch (line[0]) { case 0x2C: map1.Add(line[3], line[7]); break; case 0x48: map2.Add(line[3], line[7]); break; case 0x7c: break; default: throw new FormatException("Unrecognized line in Tracklist Modifier code: " + string.Join("", line.Select(b => ((int)b).ToString("X2")))); } } break; } } } this.StageIdMap = new Dictionary <byte, byte>(); foreach (var pair in map1) { if (map2.TryGetValue(pair.Value, out byte newStageId)) { StageIdMap.Add(pair.Key, newStageId); } else { throw new FormatException($"Part 2 of Tracklist Modifier uses ID {pair.Value} not present in Part 3"); } } }
private void init(byte[] data) { OtherCodesIgnoredInSameFile = 0; IgnoredMetadata = false; int index = -1; for (int line = 0; line < data.Length; line += 8) { if (ByteUtilities.ByteArrayEquals(data, line, SSS_HEADER, 0, SSS_HEADER.Length)) { if (index != -1) { OtherCodesIgnoredInSameFile++; } index = line; } } if (index < 0) { if (data.Length > 0) { MessageBox.Show("No custom SSS code found. A default code will be used."); } DataBefore = gctheader.ToArray(); sss1 = ByteUtilities.StringToByteArray( "00010203 04050709 080A0B0C 0D0E0F10 11141516 1A191217 0618131D 1E1B1C"); sss2 = ByteUtilities.StringToByteArray("1F202122 23242526 2728"); sss3 = ByteUtilities.StringToByteArray( "01010202 03030404 05050606 07070808 0909330A 0B0B0C0C 0D0D0E0E 130F1410 " + "15111612 17131814 19151C16 1D171E18 1F19201A 211B221C 231D241E 251F2932 " + "2A332B34 2C352D36 2F373038 3139323A 2E3BFFFF"); DataAfter = data.Skip(gctheader.Length).ToArray(); } else { int start = index; DataBefore = new byte[start]; Array.ConstrainedCopy(data, 0, DataBefore, 0, start); index += 14 * 8; byte sss1_count = data[index - 1]; sss1 = new byte[sss1_count]; Array.ConstrainedCopy(data, index, sss1, 0, sss1_count); index += sss1_count; while (index % 8 != 0) { index++; } index += 2 * 8; byte sss2_count = data[index - 1]; sss2 = new byte[sss2_count]; Array.ConstrainedCopy(data, index, sss2, 0, sss2_count); index += sss2_count; while (index % 8 != 0) { index++; } index += 1 * 8; byte sss3_count = data[index - 1]; sss3 = new byte[sss3_count]; Array.ConstrainedCopy(data, index, sss3, 0, sss3_count); index += sss3_count; while (index % 8 != 0) { index++; } DataAfter = new byte[data.Length - index]; Array.ConstrainedCopy(data, index, DataAfter, 0, data.Length - index); } bool footer_found = false; for (int i = 0; i < DataAfter.Length; i += 8) { if (footer_found) { IgnoredMetadata = true; DataAfter = DataAfter.Take(i).ToArray(); break; } else { if (ByteUtilities.ByteArrayEquals(DataAfter, i, gctfooter, 0, 8)) { footer_found = true; } } } }
public AltStageSongForcer(byte[] data) { songReplacements = new List <SongReplacement>(); for (int lineskip = 0; lineskip < data.Length; lineskip += 8) { if (ByteUtilities.ByteArrayEquals(data, lineskip, HEADER, 0, HEADER.Length)) { lineskip += HEADER.Length; using (MemoryStream ms = new MemoryStream(data, lineskip, data.Length - lineskip)) { byte stageID = 0; ushort buttons = 0; ushort?songID = null; byte[] line = new byte[4]; while (true) { int read = ms.Read(line, 0, 4); if (read < 8) { throw new FormatException(); } if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x2C, 0x1B, 0x00 }, 0, 3)) { stageID = line[3]; buttons = 0; songID = null; } else if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x2C, 0x0C }, 0, 2)) { buttons = (ushort)(line[2] << (8 + line[3])); } else if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x2C, 0x00 }, 0, 2)) { songID = (ushort)(line[2] << (8 + line[3])); } else if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x38, 0x00 }, 0, 2)) { ushort replacementSongID = (ushort)(line[2] << (8 + line[3])); songReplacements.Add(new SongReplacement { stageID = stageID, buttons = buttons, songID = songID, song = (from g in SongIDMap.Songs where g.ID == replacementSongID select g).First() }); } else if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x40, 0x82, 0x00 }, 0, 3)) { } else if (ByteUtilities.ByteArrayEquals(line, 0, new byte[] { 0x90, 0x1D, 0x00, 0x00 }, 0, 4)) { break; } else { throw new FormatException(); } } } break; } } }
public AlternateStageLoaderData(byte[] data) { AlternatesByStage = new Dictionary <string, AlternateStageEntry>(); for (int index = 0; index < data.Length; index += 8) { if (ByteUtilities.ByteArrayEquals(data, index, HEADER_BRAWL, 0, HEADER_BRAWL.Length) || ByteUtilities.ByteArrayEquals(data, index, HEADER_PM36, 0, HEADER_PM36.Length)) { int countbyte = data[index + 19]; index += 24; int endIndex = index + 8 * countbyte - 8; while (index < endIndex) { char[] name = new char[4]; name[0] = (char)data[index]; name[1] = (char)data[index + 1]; name[2] = (char)data[index + 2]; name[3] = (char)data[index + 3]; if (name[0] == '\0') { throw new Exception("Invalid stage name in alternate stage loader data: " + string.Join("", name.Select(c => ((int)c).ToString("X2")))); } Console.WriteLine(new string(name) + " " + data[index + 3].ToString("X2")); int buttonActivatedCount = data[index + 4]; if (buttonActivatedCount > 26) { throw new Exception("There are more than 26 button activated alternate stages for stage " + new string(name) + ". This is probably incorrect."); } int randomCount = data[index + 5]; if (randomCount > 26) { throw new Exception("There are more than 26 random alternate stages for stage " + new string(name) + ". This is probably incorrect."); } index += 8; List <AlternateStageEntry.Alternate> buttonActivated = new List <AlternateStageEntry.Alternate>(); for (int j = 0; j < buttonActivatedCount; j++) { int buttonMask = data[index] << (8 + data[index + 1]); char letter = (char)('A' + data[index + 3]); buttonActivated.Add(new AlternateStageEntry.Alternate { ButtonMask = (ushort)buttonMask, Letter = letter }); index += 8; } List <AlternateStageEntry.Alternate> random = new List <AlternateStageEntry.Alternate>(); for (int j = 0; j < randomCount; j++) { char letter = (char)('A' + j); random.Add(new AlternateStageEntry.Alternate { Letter = letter, ButtonMask = 0 }); } AlternatesByStage.Add(new string(name), new AlternateStageEntry { Random = random, ButtonActivated = buttonActivated }); } break; } } }
private void init(byte[] data) { Settings = new Dictionary <ushort, byte>(); int index = -1; for (int line = 0; line < data.Length; line += 8) { if (ByteUtilities.ByteArrayEquals(data, line, CSV_HEADER, 0, CSV_HEADER.Length)) { index = line; } } if (index < 0) { Console.WriteLine("No Custom Song Volume code found. An empty code will be created."); DataBefore = gctheader.ToArray(); DataAfter = data.Skip(gctheader.Length).ToArray(); } else { int start = index; DataBefore = new byte[start]; Array.ConstrainedCopy(data, 0, DataBefore, 0, start); index += 9 * 8; byte byte_count = data[index - 1]; bool found_terminator = false; for (int i = 0; i < byte_count; i += 4) { ushort u = (ushort)(data[index + i] * 0x100 + data[index + i + 1]); if (u == 0x7FFF) { if (found_terminator) { throw new InvalidDataException("Two terminators"); } found_terminator = true; } else { Settings.Add(u, data[index + i + 3]); } } if (!found_terminator) { throw new InvalidDataException("No terminators"); } index += byte_count; while (index % 8 != 0) { index++; } DataAfter = new byte[data.Length - index]; Array.ConstrainedCopy(data, index, DataAfter, 0, data.Length - index); } bool footer_found = false; for (int i = 0; i < DataAfter.Length; i += 8) { if (footer_found) { MessageBox.Show("Extra data found after GCT footer - this will be discarded if you save the GCT."); DataAfter = DataAfter.Take(i).ToArray(); break; } else { if (ByteUtilities.ByteArrayEquals(DataAfter, i, gctfooter, 0, 8)) { footer_found = true; } } } }