From da9c95c38e5a7c73eff9c39d1a3665bc43f61893 Mon Sep 17 00:00:00 2001
From: taotao54321 <taotao54321@gmail.com>
Date: Fri, 9 Mar 2012 09:24:47 +0000
Subject: [PATCH] Implemented ImportMCM()

---
 BizHawk.MultiClient/movie/MovieImport.cs | 88 +++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)

diff --git a/BizHawk.MultiClient/movie/MovieImport.cs b/BizHawk.MultiClient/movie/MovieImport.cs
index 6a3c5c2191..1272beba4c 100644
--- a/BizHawk.MultiClient/movie/MovieImport.cs
+++ b/BizHawk.MultiClient/movie/MovieImport.cs
@@ -851,12 +851,98 @@ namespace BizHawk.MultiClient
 		}
 
 		// MCM file format: http://code.google.com/p/mednafen-rr/wiki/MCM
+		//   Mednafen-rr switched to MC2 from r261, so see r260 for details.
 		private static Movie ImportMCM(string path, out string errorMsg, out string warningMsg)
 		{
+			const string SIGNATURE = "MDFNMOVI";
+			const int MOVIE_VERSION = 1;
+			const string CONSOLE_PCE = "pce";
+			const string CTRL_TYPE_PCE = "PC Engine Controller";
+			string[] CTRL_BUTTONS = {
+				"B1", "B2", "Select", "Run", "Up", "Right", "Down", "Left"
+			};
+			const int INPUT_SIZE_PCE = 11;
+			const int INPUT_PORT_COUNT = 5;
+
 			errorMsg = "";
 			warningMsg = "";
 			Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY);
+
+			// Unless otherwise noted, all values are little-endian.
+			FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
+			BinaryReader r = new BinaryReader(fs);
+			// 000 8-byte signature: 4D 44 46 4E 4D 4F 56 49 "MDFNMOVI"
+			string signature = r.ReadStringFixedAscii(SIGNATURE.Length);
+			if (signature != SIGNATURE)
+			{
+				errorMsg = "This is not a valid .MCM file.";
+				goto FAIL;
+			}
+			// 008 uint32: emulator version, current is 0x0000080A
+			uint emuVersion = r.ReadUInt32();
+			m.Header.Comments.Add(EMULATIONORIGIN + " Mednafen " + emuVersion.ToString());
+			// 00C uint32: movie format version, must be 1
+			uint version = r.ReadUInt32();
+			if (version != MOVIE_VERSION)
+			{
+				errorMsg = ".MCM movie version must always be 1.";
+				goto FAIL;
+			}
+			m.Header.Comments.Add(MOVIEORIGIN + " .MCM version " + version);
+			// 010 32-byte (actually, 16-byte) md5sum of the ROM used
+			byte[] MD5 = r.ReadBytes(16);
+			r.ReadBytes(16); // discard
+			m.Header.SetHeaderLine("MD5", BizHawk.Util.BytesToHexString(MD5).ToLower());
+			// 030 64-byte filename of ROM used (with extension)
+			string gameName = RemoveNull(r.ReadStringFixedAscii(64));
+			m.Header.SetHeaderLine(MovieHeader.GAMENAME, gameName);
+			// 070 uint32: re-record count
+			uint rerecordCount = r.ReadUInt32();
+			m.SetRerecords((int)rerecordCount);
+			// 074 5-byte console indicator (pce, ngp, pcfx, wswan)
+			string console = RemoveNull(r.ReadStringFixedAscii(5));
+			if (console != CONSOLE_PCE) // for now, bizhawk does not support ngp, pcfx, wswan
+			{
+				errorMsg = "Only PCE movies are supported.";
+				goto FAIL;
+			}
+			string platform = "PCE";
+			m.Header.SetHeaderLine(MovieHeader.PLATFORM, platform);
+			// 079 32-byte author name
+			string author = RemoveNull(r.ReadStringFixedAscii(32));
+			m.Header.SetHeaderLine(MovieHeader.AUTHOR, author);
+			// 099 103-byte padding 0s
+			r.ReadBytes(103); // discard
+
+			// 100 variable: input data
+			//   For PCE, BizHawk does not have any control command. So I ignore any command.
+			for (byte[] input = r.ReadBytes(INPUT_SIZE_PCE);
+			     input.Length == INPUT_SIZE_PCE; 
+			     input = r.ReadBytes(INPUT_SIZE_PCE))
+			{
+				SimpleController controllers = new SimpleController();
+				controllers.Type = new ControllerDefinition();
+				controllers.Type.Name = CTRL_TYPE_PCE;
+				for (int player = 1; player <= INPUT_PORT_COUNT; ++player)
+				{
+					byte pad = input[1+2*(player-1)];
+					for(int i = 0; i < 8; ++i)
+					{
+						if ((pad & (1<<i)) != 0)
+							controllers["P" + player + " " + CTRL_BUTTONS[i]] = true;
+					}
+				}
+				MnemonicsGenerator mg = new MnemonicsGenerator();
+				mg.SetSource(controllers);
+				m.AppendFrame(mg.GetControllersAsMnemonic());
+			}
+
 			return m;
+
+FAIL:
+			r.Close();
+			fs.Close();
+			return null;
 		}
 
 		// MC2 file format: http://code.google.com/p/pcejin/wiki/MC2
@@ -1354,4 +1440,4 @@ namespace BizHawk.MultiClient
 			return m;
 		}
 	}
-}
\ No newline at end of file
+}