static FileIDResult Test_UNIF(IdentifyJob job) { if (!CheckMagic(job.Stream, SimpleMagics.UNIF)) { return(new FileIDResult()); } //TODO - simple parser (for starters, check for a known chunk being next, see http://wiki.nesdev.com/w/index.php/UNIF) var ret = new FileIDResult(FileIDType.UNIF, 100); return(ret); }
static FileIDResult Test_Simple(IdentifyJob job, FileIDType type, SimpleMagicRecord magic) { var ret = new FileIDResult(type); if (CheckMagic(job.Stream, magic)) { return(new FileIDResult(type, 100)); } else { return(new FileIDResult()); } }
static FileIDResult Test_INES(IdentifyJob job) { if (!CheckMagic(job.Stream, SimpleMagics.INES)) { return(new FileIDResult()); } var ret = new FileIDResult(FileIDType.INES, 100); //an INES file should be a multiple of 8k, with the 16 byte header. //if it isnt.. this is fishy. if (((job.Stream.Length - 16) & (8 * 1024 - 1)) != 0) { ret.Confidence = 50; } return(ret); }
static FileIDResult Test_N64(IdentifyJob job) { // .Z64 = No swapping // .N64 = Word Swapped // .V64 = Byte Swapped //not sure how to check for these yet... var ret = new FileIDResult(FileIDType.N64, 5); if (job.Extension == "V64") { ret.ExtraInfo["byteswap"] = true; } if (job.Extension == "N64") { ret.ExtraInfo["wordswap"] = true; } return(ret); }
static FileIDResult Test_GB_GBC(IdentifyJob job) { if (!CheckMagic(job.Stream, SimpleMagics.GB)) { return(new FileIDResult()); } var ret = new FileIDResult(FileIDType.GB, 100); int type = ReadByte(job.Stream, 0x143); if ((type & 0x80) != 0) { ret.FileIDType = FileIDType.GBC; } //could check cart type and rom size for extra info if necessary return(ret); }
static FileIDResult Test_BIN_ISO(IdentifyJob job) { //ok, this is complicated. //there are lots of mislabeled bins/isos so lets just treat them the same (mostly) //if the BIN cant be recognized, but it is small, it is more likely some other rom BIN than a disc (turbocd or other) if (job.Extension == "BIN") { //first we can check for SMD magic words. //since this extension is ambiguous, we can't be completely sure about it. but it's almost surely accurate if (CheckMagic(job.Stream, SimpleMagics.SEGAGENESIS)) { var ret = new FileIDResult(FileIDType.SMD, 95); ret.ExtraInfo["type"] = "genesis"; return(ret); } if (CheckMagic(job.Stream, SimpleMagics.SEGAMEGADRIVE)) { var ret = new FileIDResult(FileIDType.SMD, 95); ret.ExtraInfo["type"] = "megadrive"; } } //well... guess it's a disc. //since it's just a bin, we dont need the user to provide a DiscSystem disc. //lets just analyze this as best we can. //of course, it's a lot of redundant logic with the discsystem disc checker. //but you kind of need different approaches when loading a hugely unstructured bin file //discsystem won't really even be happy mounting a .bin anyway, and we don't want it to be //for PSX, we have a magic word to look for. //it's at 0x24E0 with a mode2 (2352 byte) track 1. //what if its 2048 byte? //i found a ".iso" which was actually 2352 byte sectors.. //found a hilarious ".bin.iso" which was actually 2352 byte sectors //so, I think it's possible that every valid PSX disc is mode2 in the track 1 if (CheckMagic(job.Stream, SimpleMagics.PSX)) { var ret = new FileIDResult(FileIDType.PSX, 95); //this is an unreliable way to get a PSX game! ret.ExtraInfo["unreliable"] = true; return(ret); } //it's not proven that this is reliable. this is actually part of the Mode 1 CDFS header. perhaps it's mobile? //if it's mobile, we'll need to mount it as an ISO file here via discsystem if (CheckMagic(job.Stream, SimpleMagics.PSP)) { return(new FileIDResult(FileIDType.PSP, 95)); } //if this was an ISO, we might discover the magic word at offset 0... //if it was a mode2/2352 bin, we might discover it at offset 16 (after the data sector header) if (CheckMagic(job.Stream, SimpleMagics.SEGASATURN, 0)) { return(new FileIDResult(FileIDType.Saturn, job.Extension == "ISO" ? 95 : 90)); } if (CheckMagic(job.Stream, SimpleMagics.SEGASATURN, 16)) { return(new FileIDResult(FileIDType.Saturn, job.Extension == "BIN" ? 95 : 90)); } if (CheckMagic(job.Stream, SimpleMagics.SEGADISCSYSTEM, 0)) { return(new FileIDResult(FileIDType.MegaCD, job.Extension == "ISO" ? 95 : 90)); } if (CheckMagic(job.Stream, SimpleMagics.SEGADISCSYSTEM, 16)) { return(new FileIDResult(FileIDType.MegaCD, job.Extension == "BIN" ? 95 : 90)); } if (job.Extension == "ISO") { return(new FileIDResult(FileIDType.Disc, 1)); } else { return(new FileIDResult(FileIDType.Multiple, 1)); } }
/// <summary> /// performs wise heuristics to identify a file. /// this will attempt to return early if a confident result can be produced. /// </summary> public FileIDResults Identify(IdentifyParams p) { IdentifyJob job = new IdentifyJob() { Stream = p.SeekableStream, Disc = p.Disc }; //if we have a disc, that's a separate codepath if (job.Disc != null) { return(IdentifyDisc(job)); } FileIDResults ret = new FileIDResults(); string ext = p.Extension; if (ext != null) { ext = ext.TrimStart('.').ToUpper(); job.Extension = ext; } if (job.Extension == "CUE") { ret.ShouldTryDisc = true; return(ret); } if (job.Extension != null) { //first test everything associated with this extension ExtensionInfo handler = null; if (ExtensionHandlers.TryGetValue(ext, out handler)) { foreach (var del in handler.Testers) { var fidr = del(job); if (fidr.FileIDType == FileIDType.None) { continue; } ret.Add(fidr); } ret.Sort(); //add a low confidence result just based on extension, if it doesnt exist if (ret.Find((x) => x.FileIDType == handler.DefaultForExtension) == null) { var fidr = new FileIDResult(handler.DefaultForExtension, 5); ret.Add(fidr); } } } ret.Sort(); //if we didnt find anything high confidence, try all the testers (TODO) return(ret); }