-Added CRC header items for formats that don't store any other reference to the ROM file.

--Added Checksum / GameCode for ImportVBM because those seem more relevant.
-ImportVMV has problems with resets. Not a high priority, but still something worth looking into.
-Parsed the header for ImportZMV. The remainder looks pretty ugly...
This commit is contained in:
brandman211 2012-09-15 18:46:41 +00:00
parent 61a1556f69
commit 5682f8dbe2
1 changed files with 155 additions and 53 deletions

View File

@ -291,7 +291,9 @@ namespace BizHawk.MultiClient
else if (line.ToLower().StartsWith("sub")) else if (line.ToLower().StartsWith("sub"))
m = ImportTextSubtitle(line, m, path); m = ImportTextSubtitle(line, m, path);
else if (line.ToLower().StartsWith("emuversion")) else if (line.ToLower().StartsWith("emuversion"))
m.Header.Comments.Add(EMULATIONORIGIN + " " + emulator + " version " + ParseHeader(line, "emuVersion")); m.Header.Comments.Add(
EMULATIONORIGIN + " " + emulator + " version " + ParseHeader(line, "emuVersion")
);
else if (line.ToLower().StartsWith("version")) else if (line.ToLower().StartsWith("version"))
{ {
string version = ParseHeader(line, "version"); string version = ParseHeader(line, "version");
@ -461,12 +463,12 @@ namespace BizHawk.MultiClient
// other: reserved, set to 0 // other: reserved, set to 0
bool syncHack = (((flags >> 4) & 1) == 1); bool syncHack = (((flags >> 4) & 1) == 1);
m.Header.Comments.Add(SYNCHACK + " " + syncHack.ToString()); m.Header.Comments.Add(SYNCHACK + " " + syncHack.ToString());
/* // 009 1-byte flags: reserved, set to 0
009 1-byte flags: reserved, set to 0 r.ReadByte();
00A 1-byte flags: reserved, set to 0 // 00A 1-byte flags: reserved, set to 0
00B 1-byte flags: reserved, set to 0 r.ReadByte();
*/ // 00B 1-byte flags: reserved, set to 0
r.ReadBytes(3); r.ReadByte();
// 00C 4-byte little-endian unsigned int: number of frames // 00C 4-byte little-endian unsigned int: number of frames
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 010 4-byte little-endian unsigned int: rerecord count // 010 4-byte little-endian unsigned int: rerecord count
@ -735,8 +737,8 @@ namespace BizHawk.MultiClient
return m; return m;
} }
/* /*
The file format has no means of identifying NTSC/"PAL". It is always assumed that the game is NTSC - that is, 60 The file format has no means of identifying NTSC/"PAL". It is always assumed that the game is NTSC - that is,
fps. 60 fps.
*/ */
m.Header.SetHeaderLine("PAL", "False"); m.Header.SetHeaderLine("PAL", "False");
// 090 frame data begins here // 090 frame data begins here
@ -825,8 +827,9 @@ namespace BizHawk.MultiClient
// 016 special flags (Version A and up only) // 016 special flags (Version A and up only)
byte flags = r.ReadByte(); byte flags = r.ReadByte();
/* /*
bit 7 (most significant): if "1", movie runs at 50 frames per second; if "0", movie runs at 60 frames per second bit 7 (most significant): if "1", movie runs at 50 frames per second; if "0", movie runs at 60 frames per
The file format has no means of identifying NTSC/"PAL", but the FPS can still be derived from the header. second The file format has no means of identifying NTSC/"PAL", but the FPS can still be derived from the
header.
*/ */
bool pal = (((flags >> 7) & 1) == 1); bool pal = (((flags >> 7) & 1) == 1);
m.Header.SetHeaderLine("PAL", pal.ToString()); m.Header.SetHeaderLine("PAL", pal.ToString());
@ -851,8 +854,8 @@ namespace BizHawk.MultiClient
MnemonicsGenerator mg = new MnemonicsGenerator(); MnemonicsGenerator mg = new MnemonicsGenerator();
/* /*
040 frame data 040 frame data
For controller bytes, each value is determined by OR-ing together values for whichever of the following are left For controller bytes, each value is determined by OR-ing together values for whichever of the following are
unpressed: left unpressed:
* 0x01 Up * 0x01 Up
* 0x02 Down * 0x02 Down
* 0x04 Left * 0x04 Left
@ -1001,6 +1004,7 @@ namespace BizHawk.MultiClient
else if (item.name.StartsWith("moviesram.")) else if (item.name.StartsWith("moviesram."))
{ {
errorMsg = "Movies that begin with SRAM are not supported."; errorMsg = "Movies that begin with SRAM are not supported.";
hf.Unbind();
return null; return null;
} }
else if (item.name == "rerecords") else if (item.name == "rerecords")
@ -1102,8 +1106,9 @@ namespace BizHawk.MultiClient
{ {
{ {
/* /*
Normally, NES receives from 5 input ports, where the first 4 have a length of 1 byte, and the last has a Normally, NES receives from 5 input ports, where the first 4 have a length of 1 byte, and the last has
length of 0. For the sake of simplicity, it is interpreted as 4 ports of 1 byte length for re-recording. a length of 0. For the sake of simplicity, it is interpreted as 4 ports of 1 byte length for
re-recording.
*/ */
"nes", new Dictionary<string, object> "nes", new Dictionary<string, object>
{ {
@ -1337,8 +1342,8 @@ namespace BizHawk.MultiClient
return null; return null;
} }
/* /*
Individual blocks begin with an 8-byte header, consisting of a 4-byte signature and a 4-byte length (which does Individual blocks begin with an 8-byte header, consisting of a 4-byte signature and a 4-byte length (which
not include the length of the block header). does not include the length of the block header).
The final block in the file is of type "NMOV" The final block in the file is of type "NMOV"
*/ */
string header = r.ReadStringFixedAscii(4); string header = r.ReadStringFixedAscii(4);
@ -1355,8 +1360,8 @@ namespace BizHawk.MultiClient
// 001 1-byte controller #2 type (or four-score mask, see below) // 001 1-byte controller #2 type (or four-score mask, see below)
byte controller2 = r.ReadByte(); byte controller2 = r.ReadByte();
/* /*
Controller data is variant, depending on which controllers are attached at the time of recording. The following Controller data is variant, depending on which controllers are attached at the time of recording. The
controllers are implemented: following controllers are implemented:
* 0 - Unconnected * 0 - Unconnected
* 1 - Standard Controller (1 byte) * 1 - Standard Controller (1 byte)
* 2 - Zapper (3 bytes) * 2 - Zapper (3 bytes)
@ -1420,8 +1425,8 @@ namespace BizHawk.MultiClient
// 002 1-byte expansion port controller type // 002 1-byte expansion port controller type
byte expansion = r.ReadByte(); byte expansion = r.ReadByte();
/* /*
The expansion port can potentially have an additional controller connected. The following expansion controllers The expansion port can potentially have an additional controller connected. The following expansion
are implemented: controllers are implemented:
* 0 - Unconnected * 0 - Unconnected
* 1 - Famicom 4-player adapter (2 bytes) * 1 - Famicom 4-player adapter (2 bytes)
* 2 - Famicom Arkanoid paddle (2 bytes) * 2 - Famicom Arkanoid paddle (2 bytes)
@ -1572,7 +1577,11 @@ namespace BizHawk.MultiClient
* bit 4: controller 5 in use * bit 4: controller 5 in use
* other: reserved, set to 0 * other: reserved, set to 0
*/ */
for (int controller = 1; controller <= 5; controller++) SimpleController controllers = new SimpleController();
controllers.Type = new ControllerDefinition();
controllers.Type.Name = "SNES Controller";
MnemonicsGenerator mg = new MnemonicsGenerator();
for (int controller = 1; controller <= Global.PLAYERS[controllers.Type.Name]; controller++)
if (((controllerFlags >> (controller - 1)) & 0x1) != 0) if (((controllerFlags >> (controller - 1)) & 0x1) != 0)
players++; players++;
// 015 1-byte flags "movie options" // 015 1-byte flags "movie options"
@ -1662,10 +1671,6 @@ namespace BizHawk.MultiClient
m.Header.SetHeaderLine(MovieHeader.GAMENAME, gameName); m.Header.SetHeaderLine(MovieHeader.GAMENAME, gameName);
} }
r.BaseStream.Position = firstFrameOffset; r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController();
controllers.Type = new ControllerDefinition();
controllers.Type.Name = "SNES Controller";
MnemonicsGenerator mg = new MnemonicsGenerator();
/* /*
01 00 (reserved) 01 00 (reserved)
02 00 (reserved) 02 00 (reserved)
@ -1744,7 +1749,7 @@ namespace BizHawk.MultiClient
break; break;
} }
if (warningMsg != "" && peripheral != "") if (warningMsg != "" && peripheral != "")
warningMsg = peripheral; warningMsg = "Unable to import " + peripheral + ".";
} }
ushort controllerState = (ushort)(((controllerState1 << 4) & 0x0F00) | controllerState2); ushort controllerState = (ushort)(((controllerState1 << 4) & 0x0F00) | controllerState2);
for (int button = 0; button < buttons.Length; button++) for (int button = 0; button < buttons.Length; button++)
@ -1898,8 +1903,8 @@ namespace BizHawk.MultiClient
* laggy GBA timing. * laggy GBA timing.
* bit 5: (gbcHdma5Fix) if "0" and the movie is of a GBC game, the movie was made using the old buggy HDMA5 * bit 5: (gbcHdma5Fix) if "0" and the movie is of a GBC game, the movie was made using the old buggy HDMA5
* timing. * timing.
* bit 6: (echoRAMFix) if "1" and the movie is of a GB, GBC, or SGB game, the movie was made with Echo RAM Fix * bit 6: (echoRAMFix) if "1" and the movie is of a GB, GBC, or SGB game, the movie was made with Echo RAM
* on, otherwise it was made with Echo RAM Fix off. * Fix on, otherwise it was made with Echo RAM Fix off.
* bit 7: reserved, set to 0. * bit 7: reserved, set to 0.
*/ */
/* /*
@ -1924,12 +1929,16 @@ namespace BizHawk.MultiClient
032 2-byte little-endian unsigned short: the internal Checksum of the ROM used while recording, or a 032 2-byte little-endian unsigned short: the internal Checksum of the ROM used while recording, or a
calculated CRC16 of the BIOS if GBA calculated CRC16 of the BIOS if GBA
*/ */
r.ReadBytes(2); ushort checksum = r.ReadUInt16();
/* /*
034 4-byte little-endian unsigned int: the Game Code of the ROM used while recording, or the Unit Code if not 034 4-byte little-endian unsigned int: the Game Code of the ROM used while recording, or the Unit Code if not
GBA GBA
*/ */
r.ReadBytes(4); uint gameCode = r.ReadUInt32();
if (platform == "GBA")
m.Header.SetHeaderLine("GameCode", gameCode.ToString());
else
m.Header.SetHeaderLine("Checksum", checksum.ToString());
// 038 4-byte little-endian unsigned int: offset to the savestate or SRAM inside file, set to 0 if unused // 038 4-byte little-endian unsigned int: offset to the savestate or SRAM inside file, set to 0 if unused
r.ReadBytes(4); r.ReadBytes(4);
// 03C 4-byte little-endian unsigned int: offset to the controller data inside file // 03C 4-byte little-endian unsigned int: offset to the controller data inside file
@ -1973,8 +1982,8 @@ namespace BizHawk.MultiClient
for (int frame = 1; frame <= frameCount; frame++) for (int frame = 1; frame <= frameCount; frame++)
{ {
/* /*
A stream of 2-byte bitvectors which indicate which buttons are pressed at each point in time. They will come A stream of 2-byte bitvectors which indicate which buttons are pressed at each point in time. They will
in groups of however many controllers are active, in increasing order. come in groups of however many controllers are active, in increasing order.
*/ */
ushort controllerState = r.ReadUInt16(); ushort controllerState = r.ReadUInt16();
for (int button = 0; button < buttons.Length; button++) for (int button = 0; button < buttons.Length; button++)
@ -2054,12 +2063,12 @@ namespace BizHawk.MultiClient
bit 7: disable rerecording bit 7: disable rerecording
Other bits: reserved, set to 0 Other bits: reserved, set to 0
*/ */
/* // 014 DWORD Ext0; // ROM:program CRC FDS:program ID
014 DWORD Ext0; // ROM:program CRC FDS:program ID r.ReadBytes(4);
018 WORD Ext1; // ROM:unused,0 FDS:maker ID // 018 WORD Ext1; // ROM:unused,0 FDS:maker ID
01A WORD Ext2; // ROM:unused,0 FDS:disk no. r.ReadBytes(2);
*/ // 01A WORD Ext2; // ROM:unused,0 FDS:disk no.
r.ReadUInt64(); r.ReadBytes(2);
// 01C 4-byte little-endian integer: rerecord count // 01C 4-byte little-endian integer: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = (int)rerecordCount;
@ -2068,25 +2077,28 @@ namespace BizHawk.MultiClient
0=POST_ALL,1=PRE_ALL 0=POST_ALL,1=PRE_ALL
2=POST_RENDER,3=PRE_RENDER 2=POST_RENDER,3=PRE_RENDER
4=TILE_RENDER 4=TILE_RENDER
021 BYTE IRQtype // IRQ type
022 BYTE FrameIRQ // FrameIRQ not allowed
*/ */
r.ReadBytes(3); r.ReadByte();
// 021 BYTE IRQtype // IRQ type
r.ReadByte();
// 022 BYTE FrameIRQ // FrameIRQ not allowed
r.ReadByte();
// 023 1-byte flag: 0=NTSC (60 Hz), 1="PAL" (50 Hz) // 023 1-byte flag: 0=NTSC (60 Hz), 1="PAL" (50 Hz)
bool pal = (r.ReadByte() == 1); bool pal = (r.ReadByte() == 1);
m.Header.SetHeaderLine("PAL", pal.ToString()); m.Header.SetHeaderLine("PAL", pal.ToString());
/* // 024 8-bytes: reserved, set to 0
024 8-bytes: reserved, set to 0 r.ReadBytes(8);
02C 4-byte little-endian integer: save state start offset // 02C 4-byte little-endian integer: save state start offset
030 4-byte little-endian integer: save state end offset r.ReadBytes(4);
*/ // 030 4-byte little-endian integer: save state end offset
r.ReadBytes(16); r.ReadBytes(4);
// 034 4-byte little-endian integer: movie data offset // 034 4-byte little-endian integer: movie data offset
uint firstFrameOffset = r.ReadUInt32(); uint firstFrameOffset = r.ReadUInt32();
// 038 4-byte little-endian integer: movie frame count // 038 4-byte little-endian integer: movie frame count
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 03C 4-byte little-endian integer: CRC (CRC excluding this data(to prevent cheating)) // 03C 4-byte little-endian integer: CRC (CRC excluding this data(to prevent cheating))
r.ReadUInt32(); int crc32 = r.ReadInt32();
m.Header.SetHeaderLine("CRC32", crc32.ToString());
if (!controller1 && !controller2 && !controller3 && !controller4) if (!controller1 && !controller2 && !controller3 && !controller4)
{ {
warningMsg = "No input recorded."; warningMsg = "No input recorded.";
@ -2116,9 +2128,9 @@ namespace BizHawk.MultiClient
/* /*
For the other control bytes, if a key from 1P to 4P (whichever one) is entirely ON, the following 4 bytes For the other control bytes, if a key from 1P to 4P (whichever one) is entirely ON, the following 4 bytes
becomes the controller data (TODO: Figure out what this means). becomes the controller data (TODO: Figure out what this means).
Each frame consists of 1 or more bytes. Controller 1 takes 1 byte, controller 2 takes 1 byte, controller 3 Each frame consists of 1 or more bytes. Controller 1 takes 1 byte, controller 2 takes 1 byte, controller
takes 1 byte, and controller 4 takes 1 byte. If all four exist, the frame is 4 bytes. For example, if the 3 takes 1 byte, and controller 4 takes 1 byte. If all four exist, the frame is 4 bytes. For example, if
movie only has controller 1 data, a frame is 1 byte. the movie only has controller 1 data, a frame is 1 byte.
*/ */
for (int player = 1; player <= masks.Length; player++) for (int player = 1; player <= masks.Length; player++)
{ {
@ -2143,7 +2155,97 @@ namespace BizHawk.MultiClient
errorMsg = ""; errorMsg = "";
warningMsg = ""; warningMsg = "";
Movie m = new Movie(path + "." + Global.Config.MovieExtension); Movie m = new Movie(path + "." + Global.Config.MovieExtension);
// TODO: Import. FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
// 000 3-byte signature: 5A 4D 56 "ZMV"
string signature = r.ReadStringFixedAscii(3);
if (signature != "ZMV")
{
errorMsg = "This is not a valid .ZMV file.";
r.Close();
fs.Close();
return null;
}
m.Header.SetHeaderLine(MovieHeader.PLATFORM, "SNES");
// 003 2-byte little-endian unsigned int: zsnes version number
short version = r.ReadInt16();
// 005 4-byte little-endian integer: CRC32 of the ROM
int crc32 = r.ReadInt32();
m.Header.SetHeaderLine("CRC32", crc32.ToString());
// 009 4-byte little-endian unsigned int: number of frames
uint frameCount = r.ReadUInt32();
// 00D 4-byte little-endian unsigned int: number of rerecords
uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount;
// 011 4-byte little-endian unsigned int: number of frames removed by rerecord
r.ReadBytes(4);
// 015 4-byte little-endian unsigned int: number of frames advanced step by step
r.ReadBytes(4);
// 016 1-byte: average recording frames per second
r.ReadByte();
// 020 4-byte little-endian unsigned int: number of key combos
r.ReadBytes(4);
// 01E 2-byte little-endian unsigned int: number of internal chapters
r.ReadBytes(2);
// 020 2-byte little-endian unsigned int: length of the author name field in bytes
ushort authorSize = r.ReadUInt16();
// 022 3-byte little-endian unsigned int: size of an uncompressed save state in bytes
r.ReadBytes(3);
/*
025 1-byte flags: initial input configuration
bit 7: first input enabled
bit 6: second input enabled
bit 5: third input enabled
bit 4: fourth input enabled
bit 3: fifth input enabled
bit 2: first mouse input enabled
bit 1: second mouse input enabled
bit 0: super scope input enabled
*/
byte controllerFlags = r.ReadByte();
if ((controllerFlags & 0x1) != 0)
warningMsg = "Super Scope";
controllerFlags >>= 1;
if ((controllerFlags & 0x1) != 0 && warningMsg != "")
warningMsg = "Mouse";
controllerFlags >>= 1;
if (warningMsg != "")
warningMsg = "Unable to import " + warningMsg + ".";
// 026 1-byte: reserved
r.ReadByte();
// 027 1-byte flags:
byte movieFlags = r.ReadByte();
byte begins = (byte)(movieFlags & 0xC0);
/*
bits 7,6:
if "00", movie begins from savestate
*/
if (begins == 0x00)
{
errorMsg = "Movies that begin with a savestate are not supported.";
r.Close();
fs.Close();
return null;
}
// if "10", movie begins from reset
// if "01", movie begins from power-on
if (begins == 0x40)
{
errorMsg = "Movies that begin with SRAM are not supported.";
r.Close();
fs.Close();
return null;
}
// if "11", movie begins from power-on with SRAM clear
// bit 5: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps)
bool pal = (((movieFlags >> 5) & 0x1) != 0);
m.Header.SetHeaderLine("PAL", pal.ToString());
// other: reserved, set to 0
/*
028 3-byte little-endian unsigned int: initial save state size, highest bit specifies compression, next 23
specifies size
*/
r.ReadBytes(3);
return m; return m;
} }
} }