Example #1
0
        private void RunImportJob(IEnumerable <string> files)
        {
            bool   didSomething = false;
            var    basePath     = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null);
            string errors       = "";

            foreach (var f in files)
            {
                using var hf = new HawkFile(f);
                if (hf.IsArchive)
                {
                    // blech. the worst extraction code in the universe.
                    string        extractPath = $"{Path.GetTempFileName()}.dir";
                    DirectoryInfo di          = Directory.CreateDirectory(extractPath);

                    try
                    {
                        foreach (var ai in hf.ArchiveItems)
                        {
                            hf.BindArchiveMember(ai);
                            var stream = hf.GetStream();
                            var ms     = new MemoryStream();
                            Util.CopyStream(hf.GetStream(), ms, stream.Length);
                            string outfile = ai.Name;
                            string myname  = Path.GetFileName(outfile);
                            outfile = Path.Combine(extractPath, myname);
                            File.WriteAllBytes(outfile, ms.ToArray());
                            hf.Unbind();

                            if (_cbAllowImport.Checked || Manager.CanFileBeImported(outfile))
                            {
                                didSomething |= RunImportJobSingle(basePath, outfile, ref errors);
                            }
                        }
                    }
                    finally
                    {
                        di.Delete(true);
                    }
                }
                else
                {
                    if (_cbAllowImport.Checked || Manager.CanFileBeImported(hf.CanonicalFullPath))
                    {
                        didSomething |= RunImportJobSingle(basePath, f, ref errors);
                    }
                }
            }

            if (!string.IsNullOrEmpty(errors))
            {
                MessageBox.Show(errors, "Error importing these files");
            }

            if (didSomething)
            {
                DoScan();
            }
        }
        void RunImportJob(IEnumerable <string> files)
        {
            bool   didSomething = false;
            var    basepath     = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null);
            string errors       = "";

            foreach (var f in files)
            {
                using (var hf = new HawkFile(f))
                {
                    if (hf.IsArchive)
                    {
                        //blech. the worst extraction code in the universe.
                        string        extractpath = System.IO.Path.GetTempFileName() + ".dir";
                        DirectoryInfo di          = null;
                        di = System.IO.Directory.CreateDirectory(extractpath);

                        try
                        {
                            foreach (var ai in hf.ArchiveItems)
                            {
                                hf.BindArchiveMember(ai);
                                var stream = hf.GetStream();
                                var ms     = new MemoryStream();
                                Util.CopyStream(hf.GetStream(), ms, stream.Length);
                                string outfile = ai.Name;
                                string myname  = Path.GetFileName(outfile);
                                outfile = Path.Combine(extractpath, myname);
                                File.WriteAllBytes(outfile, ms.ToArray());
                                hf.Unbind();
                                didSomething |= RunImportJobSingle(basepath, outfile, ref errors);
                            }
                        }
                        finally
                        {
                            di.Delete(true);
                        }
                    }
                    else
                    {
                        didSomething |= RunImportJobSingle(basepath, f, ref errors);
                    }
                }
            }

            if (errors != "")
            {
                System.Windows.Forms.MessageBox.Show(errors, "Error importing these files");
            }

            if (didSomething)
            {
                DoScan();
            }
        }
Example #3
0
        public static XmlGame Create(HawkFile f)
        {
            try
            {
                var x = new XmlDocument();
                x.Load(f.GetStream());
                var y = x.SelectSingleNode("./BizHawk-XMLGame");
                if (y == null)
                {
                    return(null);
                }

                var ret = new XmlGame
                {
                    GI =
                    {
                        System = y.Attributes["System"].Value,
                        Name   = y.Attributes["Name"].Value,
                        Status = RomStatus.Unknown
                    },
                    Xml = x
                };

                var n = y.SelectSingleNode("./LoadAssets");
                if (n != null)
                {
                    var HashStream    = new MemoryStream();
                    int?OriginalIndex = null;

                    foreach (XmlNode a in n.ChildNodes)
                    {
                        string filename = a.Attributes["FileName"].Value;
                        byte[] data     = new byte[0];
                        if (filename[0] == '|')
                        {
                            // in same archive
                            var ai = f.FindArchiveMember(filename.Substring(1));
                            if (ai != null)
                            {
                                if (OriginalIndex == null)
                                {
                                    OriginalIndex = f.GetBoundIndex();
                                }

                                f.Unbind();
                                f.BindArchiveMember(ai);
                                data = f.GetStream().ReadAllBytes();
                            }
                            else
                            {
                                throw new Exception("Couldn't load XMLGame Asset \"" + filename + "\"");
                            }
                        }
                        else
                        {
                            // relative path
                            var fullpath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? string.Empty;
                            fullpath = Path.Combine(fullpath, filename.Split('|').First());
                            try
                            {
                                using (var hf = new HawkFile(fullpath))
                                {
                                    if (hf.IsArchive)
                                    {
                                        var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First());
                                        hf.Unbind();
                                        hf.BindArchiveMember(archiveItem);
                                        data = hf.GetStream().ReadAllBytes();
                                    }
                                    else
                                    {
                                        data = File.ReadAllBytes(fullpath.Split('|').First());
                                    }
                                }
                            }
                            catch
                            {
                                throw new Exception("Couldn't load XMLGame LoadAsset \"" + filename + "\"");
                            }
                        }

                        ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data));

                        using (var sha1 = System.Security.Cryptography.SHA1.Create())
                        {
                            sha1.TransformFinalBlock(data, 0, data.Length);
                            HashStream.Write(sha1.Hash, 0, sha1.Hash.Length);
                        }
                    }

                    ret.GI.Hash = HashStream.GetBuffer().HashSHA1(0, (int)HashStream.Length);
                    HashStream.Close();
                    if (OriginalIndex != null)
                    {
                        f.Unbind();
                        f.BindArchiveMember((int)OriginalIndex);
                    }
                }
                else
                {
                    ret.GI.Hash = "0000000000000000000000000000000000000000";
                }

                return(ret);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(ex.ToString());
            }
        }
Example #4
0
        public RomGame(HawkFile file, string patch)
        {
            if (!file.Exists)
            {
                throw new Exception("The file needs to exist, yo.");
            }

            Extension = file.Extension;

            var stream     = file.GetStream();
            int fileLength = (int)stream.Length;

            // read the entire contents of the file into memory.
            // unfortunate in the case of large files, but thats what we've got to work with for now.

            // if we're offset exactly 512 bytes from a 1024-byte boundary,
            // assume we have a header of that size. Otherwise, assume it's just all rom.
            // Other 'recognized' header sizes may need to be added.
            int headerOffset = fileLength % BankSize;

            if (headerOffset.In(0, 512) == false)
            {
                Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset);
                headerOffset = 0;
            }
            else if (headerOffset > 0)
            {
                Console.WriteLine("Assuming header of {0} bytes.", headerOffset);
            }

            // read the entire file into FileData.
            FileData = new byte[fileLength];
            stream.Read(FileData, 0, fileLength);

            // if there was no header offset, RomData is equivalent to FileData
            // (except in cases where the original interleaved file data is necessary.. in that case we'll have problems..
            // but this whole architecture is not going to withstand every peculiarity and be fast as well.
            if (headerOffset == 0)
            {
                RomData = FileData;
            }
            else
            {
                // if there was a header offset, read the whole file into FileData and then copy it into RomData (this is unfortunate, in case RomData isnt needed)
                int romLength = fileLength - headerOffset;
                RomData = new byte[romLength];
                Buffer.BlockCopy(FileData, headerOffset, RomData, 0, romLength);
            }

            if (file.Extension == ".SMD")
            {
                RomData = DeInterleaveSMD(RomData);
            }

            if (file.Extension == ".Z64" || file.Extension == ".N64" || file.Extension == ".V64")
            {
                RomData = MutateSwapN64(RomData);
            }

            // note: this will be taking several hashes, of a potentially large amount of data.. yikes!
            GameInfo = Database.GetGameInfo(RomData, file.Name);

            CheckForPatchOptions();

            if (patch != null)
            {
                using (var patchFile = new HawkFile(patch))
                {
                    patchFile.BindFirstOf("IPS");
                    if (patchFile.IsBound)
                    {
                        IPS.Patch(RomData, patchFile.GetStream());
                    }
                }
            }
        }
Example #5
0
        public BootGodDb(string basePath)
        {
            // notes: there can be multiple each of prg,chr,wram,vram
            // we aren't tracking the individual hashes yet.

            string xmlPath = Path.Combine(basePath, "NesCarts.xml");
            string x7zPath = Path.Combine(basePath, "NesCarts.7z");
            bool   loadXml = File.Exists(xmlPath);

            using var nesCartFile = new HawkFile(loadXml ? xmlPath : x7zPath);
            if (!loadXml)
            {
                nesCartFile.BindFirst();
            }

            var stream = nesCartFile.GetStream();

            // in anticipation of any slowness annoying people, and just for shits and giggles, i made a super fast parser
            int      state     = 0;
            var      xmlReader = XmlReader.Create(stream);
            CartInfo currCart  = null;
            string   currName  = null;

            while (xmlReader.Read())
            {
                switch (state)
                {
                case 0:
                    if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "game")
                    {
                        currName = xmlReader.GetAttribute("name");
                        state    = 1;
                    }
                    break;

                case 2:
                    if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "board")
                    {
                        currCart.BoardType = xmlReader.GetAttribute("type");
                        currCart.Pcb       = xmlReader.GetAttribute("pcb");
                        int mapper = int.Parse(xmlReader.GetAttribute("mapper"));
                        if (validate && mapper > 255)
                        {
                            throw new Exception("didnt expect mapper>255!");
                        }
                        // we don't actually use this value at all; only the board name
                        state = 3;
                    }
                    break;

                case 3:
                    if (xmlReader.NodeType == XmlNodeType.Element)
                    {
                        switch (xmlReader.Name)
                        {
                        case "prg":
                            currCart.PrgSize += (short)ParseSize(xmlReader.GetAttribute("size"));
                            break;

                        case "chr":
                            currCart.ChrSize += (short)ParseSize(xmlReader.GetAttribute("size"));
                            break;

                        case "vram":
                            currCart.VramSize += (short)ParseSize(xmlReader.GetAttribute("size"));
                            break;

                        case "wram":
                            currCart.WramSize += (short)ParseSize(xmlReader.GetAttribute("size"));
                            if (xmlReader.GetAttribute("battery") != null)
                            {
                                currCart.WramBattery = true;
                            }
                            break;

                        case "pad":
                            currCart.PadH = byte.Parse(xmlReader.GetAttribute("h"));
                            currCart.PadV = byte.Parse(xmlReader.GetAttribute("v"));
                            break;

                        case "chip":
                            currCart.Chips.Add(xmlReader.GetAttribute("type"));
                            if (xmlReader.GetAttribute("battery") != null)
                            {
                                currCart.WramBattery = true;
                            }
                            break;
                        }
                    }
                    else
                    if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "board")
                    {
                        state = 4;
                    }
                    break;

                case 4:
                    if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "cartridge")
                    {
                        _sha1Table[currCart.Sha1].Add(currCart);
                        currCart = null;
                        state    = 5;
                    }
                    break;

                case 5:
                case 1:
                    if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "cartridge")
                    {
                        currCart        = new CartInfo();
                        currCart.System = xmlReader.GetAttribute("system");
                        currCart.Sha1   = "sha1:" + xmlReader.GetAttribute("sha1");
                        currCart.Name   = currName;
                        state           = 2;
                    }
                    if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "game")
                    {
                        currName = null;
                        state    = 0;
                    }
                    break;
                }
            }             //end xmlreader loop
        }
Example #6
0
        protected override void RunImport()
        {
            Result.Movie.HeaderEntries[HeaderKeys.Core] = CoreNames.Bsnes;

            var hf = new HawkFile(SourceFile.FullName);

            // .LSMV movies are .zip files containing data files.
            if (!hf.IsArchive)
            {
                Result.Errors.Add("This is not an archive.");
                return;
            }

            var ss = new LibsnesCore.SnesSyncSettings
            {
                LeftPort  = LibsnesControllerDeck.ControllerType.Gamepad,
                RightPort = LibsnesControllerDeck.ControllerType.Gamepad
            };

            _deck = new LibsnesControllerDeck(ss);

            string platform = "SNES";

            foreach (var item in hf.ArchiveItems)
            {
                if (item.Name == "authors")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream     = hf.GetStream();
                    string authors    = Encoding.UTF8.GetString(stream.ReadAllBytes());
                    string authorList = "";
                    string authorLast = "";
                    using (var reader = new StringReader(authors))
                    {
                        string line;

                        // Each author is on a different line.
                        while ((line = reader.ReadLine()) != null)
                        {
                            string author = line.Trim();
                            if (author != "")
                            {
                                if (authorLast != "")
                                {
                                    authorList += $"{authorLast}, ";
                                }

                                authorLast = author;
                            }
                        }
                    }

                    if (authorList != "")
                    {
                        authorList += "and ";
                    }

                    if (authorLast != "")
                    {
                        authorList += authorLast;
                    }

                    Result.Movie.HeaderEntries[HeaderKeys.Author] = authorList;
                    hf.Unbind();
                }
                else if (item.Name == "coreversion")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream      = hf.GetStream();
                    string coreVersion = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.Comments.Add($"CoreOrigin {coreVersion}");
                    hf.Unbind();
                }
                else if (item.Name == "gamename")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream   = hf.GetStream();
                    string gameName = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries[HeaderKeys.GameName] = gameName;
                    hf.Unbind();
                }
                else if (item.Name == "gametype")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream   = hf.GetStream();
                    string gametype = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();

                    // TODO: Handle the other types.
                    switch (gametype)
                    {
                    case "gdmg":
                        platform = "GB";
                        break;

                    case "ggbc":
                    case "ggbca":
                        platform = "GBC";
                        break;

                    case "sgb_ntsc":
                    case "sgb_pal":
                        platform       = "SNES";
                        Config.GbAsSgb = true;
                        break;
                    }

                    bool pal = gametype == "snes_pal" || gametype == "sgb_pal";
                    Result.Movie.HeaderEntries[HeaderKeys.Pal] = pal.ToString();
                    hf.Unbind();
                }
                else if (item.Name == "input")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream = hf.GetStream();
                    string input  = Encoding.UTF8.GetString(stream.ReadAllBytes());

                    int lineNum = 0;
                    using (var reader = new StringReader(input))
                    {
                        lineNum++;
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            if (line == "")
                            {
                                continue;
                            }

                            // Insert an empty frame in lsmv snes movies
                            // https://github.com/TASVideos/BizHawk/issues/721
                            // Both emulators send the input to bsnes core at the same V interval, but:
                            // lsnes' frame boundary occurs at V = 241, after which the input is read;
                            // BizHawk's frame boundary is just before automatic polling;
                            // This isn't a great place to add this logic but this code is a mess
                            if (lineNum == 1 && platform == "SNES")
                            {
                                // Note that this logic assumes the first non-empty log entry is a valid input log entry
                                // and that it is NOT a subframe input entry.  It seems safe to assume subframe input would not be on the first line
                                Result.Movie.AppendFrame(EmptyLmsvFrame());
                            }

                            ImportTextFrame(line, platform);
                        }
                    }

                    hf.Unbind();
                }
                else if (item.Name.StartsWith("moviesram."))
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream    = hf.GetStream();
                    byte[] movieSram = stream.ReadAllBytes();
                    if (movieSram.Length != 0)
                    {
                        Result.Errors.Add("Movies that begin with SRAM are not supported.");
                        hf.Unbind();
                        return;
                    }
                }
                else if (item.Name == "port1")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream = hf.GetStream();
                    string port1  = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries["port1"] = port1;
                    ss.LeftPort = LibsnesControllerDeck.ControllerType.Gamepad;
                    _deck       = new LibsnesControllerDeck(ss);
                    hf.Unbind();
                }
                else if (item.Name == "port2")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream = hf.GetStream();
                    string port2  = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries["port2"] = port2;
                    ss.RightPort = LibsnesControllerDeck.ControllerType.Gamepad;
                    _deck        = new LibsnesControllerDeck(ss);
                    hf.Unbind();
                }
                else if (item.Name == "projectid")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream    = hf.GetStream();
                    string projectId = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries["ProjectID"] = projectId;
                    hf.Unbind();
                }
                else if (item.Name == "rerecords")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream    = hf.GetStream();
                    string rerecords = Encoding.UTF8.GetString(stream.ReadAllBytes());
                    int    rerecordCount;

                    // Try to parse the re-record count as an integer, defaulting to 0 if it fails.
                    try
                    {
                        rerecordCount = int.Parse(rerecords);
                    }
                    catch
                    {
                        rerecordCount = 0;
                    }

                    Result.Movie.Rerecords = (ulong)rerecordCount;
                    hf.Unbind();
                }
                else if (item.Name.EndsWith(".sha256"))
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream = hf.GetStream();
                    string rom    = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    int    pos    = item.Name.LastIndexOf(".sha256");
                    string name   = item.Name.Substring(0, pos);
                    Result.Movie.HeaderEntries[$"SHA256_{name}"] = rom;
                    hf.Unbind();
                }
                else if (item.Name == "savestate")
                {
                    Result.Errors.Add("Movies that begin with a savestate are not supported.");
                    return;
                }
                else if (item.Name == "subtitles")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream    = hf.GetStream();
                    string subtitles = Encoding.UTF8.GetString(stream.ReadAllBytes());
                    using (var reader = new StringReader(subtitles))
                    {
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            var subtitle = ImportTextSubtitle(line);
                            if (!string.IsNullOrEmpty(subtitle))
                            {
                                Result.Movie.Subtitles.AddFromString(subtitle);
                            }
                        }
                    }

                    hf.Unbind();
                }
                else if (item.Name == "starttime.second")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream      = hf.GetStream();
                    string startSecond = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries["StartSecond"] = startSecond;
                    hf.Unbind();
                }
                else if (item.Name == "starttime.subsecond")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream         = hf.GetStream();
                    string startSubSecond = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.HeaderEntries["StartSubSecond"] = startSubSecond;
                    hf.Unbind();
                }
                else if (item.Name == "systemid")
                {
                    hf.BindArchiveMember(item.Index);
                    var    stream   = hf.GetStream();
                    string systemId = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
                    Result.Movie.Comments.Add($"{EmulationOrigin} {systemId}");
                    hf.Unbind();
                }
            }

            Result.Movie.HeaderEntries[HeaderKeys.Platform] = platform;
            Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(ss);
            Config.PreferredCores["SNES"] = CoreNames.Bsnes;             // TODO: convert to snes9x if it is the user's preference
        }
Example #7
0
        /// <exception cref="Exception"><paramref name="file"/> does not exist</exception>
        public RomGame(HawkFile file, string patch)
        {
            if (!file.Exists)
            {
                throw new Exception("The file needs to exist, yo.");
            }

            Extension = file.Extension.ToUpperInvariant();

            var stream     = file.GetStream();
            int fileLength = (int)stream.Length;

            // read the entire contents of the file into memory.
            // unfortunate in the case of large files, but that's what we've got to work with for now.

            // if we're offset exactly 512 bytes from a 1024-byte boundary,
            // assume we have a header of that size. Otherwise, assume it's just all rom.
            // Other 'recognized' header sizes may need to be added.
            int headerOffset = fileLength % BankSize;

            if (headerOffset.In(0, 128, 512) == false)
            {
                Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset);
                headerOffset = 0;
            }
            else if (headerOffset > 0)
            {
                Console.WriteLine("Assuming header of {0} bytes.", headerOffset);
            }

            // read the entire file into FileData.
            FileData        = new byte[fileLength];
            stream.Position = 0;
            stream.Read(FileData, 0, fileLength);

            // if there was no header offset, RomData is equivalent to FileData
            // (except in cases where the original interleaved file data is necessary.. in that case we'll have problems..
            // but this whole architecture is not going to withstand every peculiarity and be fast as well.
            if (headerOffset == 0)
            {
                RomData = FileData;
            }
            else if (file.Extension == ".dsk" || file.Extension == ".tap" || file.Extension == ".tzx" ||
                     file.Extension == ".pzx" || file.Extension == ".csw" || file.Extension == ".wav" || file.Extension == ".cdt")
            {
                // these are not roms. unfortunately if treated as such there are certain edge-cases
                // where a header offset is detected. This should mitigate this issue until a cleaner solution is found
                // (-Asnivor)
                RomData = FileData;
            }
            else
            {
                // if there was a header offset, read the whole file into FileData and then copy it into RomData (this is unfortunate, in case RomData isn't needed)
                int romLength = fileLength - headerOffset;
                RomData = new byte[romLength];
                Buffer.BlockCopy(FileData, headerOffset, RomData, 0, romLength);
            }

            if (file.Extension == ".smd")
            {
                RomData = DeInterleaveSMD(RomData);
            }

            if (file.Extension == ".z64" || file.Extension == ".n64" || file.Extension == ".v64")
            {
                RomData = MutateSwapN64(RomData);
            }

            // note: this will be taking several hashes, of a potentially large amount of data.. yikes!
            GameInfo = Database.GetGameInfo(RomData, file.Name);

            if (GameInfo.NotInDatabase && headerOffset == 128 && file.Extension == ".a78")
            {
                // if the game is not in the DB, add the header back in so the core can use it
                // for now only .A78 games, but probably should be for other systems as well
                RomData = FileData;
            }

            CheckForPatchOptions();

            if (patch != null)
            {
                using var patchFile = new HawkFile(patch);
                patchFile.BindFirstOf(".ips");
                if (patchFile.IsBound)
                {
                    RomData = IPS.Patch(RomData, patchFile.GetStream());
                }
            }
        }
Example #8
0
        /// <summary>
        /// Load Header information only for displaying file information in dialogs such as play movie
        /// TODO - consider not loading the SavestateBinaryBase64Blob key?
        /// </summary>
        public bool PreLoadHeaderAndLength(HawkFile hawkFile)
        {
            Loaded = false;
            var file = new FileInfo(hawkFile.CanonicalFullPath);

            if (file.Exists == false)
            {
                return(false);
            }

            Header.Clear();
            _log.Clear();

            var origStreamPosn = hawkFile.GetStream().Position;

            hawkFile.GetStream().Position = 0;             // Reset to start

            // No using block because we're sharing the stream and need to give it back undisposed.
            var sr = new StreamReader(hawkFile.GetStream());

            for (;;)
            {
                // read to first space (key/value delimeter), or pipe, or EOF
                int first = sr.Read();

                if (first == -1)
                {
                    break;
                }                 // EOF

                if (first == '|') // pipe: begin input log
                {
                    // NOTE - this code is a bit convoluted due to its predating the basic outline of the parser which was upgraded in may 2014
                    var line = '|' + sr.ReadLine();

                    // how many bytes are left, total?
                    long remain = sr.BaseStream.Length - sr.BaseStream.Position;

                    // try to find out whether we use \r\n or \n
                    // but only look for 1K characters.
                    bool usesR = false;
                    for (int i = 0; i < 1024; i++)
                    {
                        int c = sr.Read();
                        if (c == -1)
                        {
                            break;
                        }

                        if (c == '\r')
                        {
                            usesR = true;
                            break;
                        }

                        if (c == '\n')
                        {
                            break;
                        }
                    }

                    int lineLen = line.Length + 1;                     // account for \n
                    if (usesR)
                    {
                        lineLen++;                         // account for \r
                    }

                    _preloadFramecount = (int)(remain / lineLen); // length is remaining bytes / length per line
                    _preloadFramecount++;                         // account for the current line
                    break;
                }
                else
                {
                    // a header line. finish reading key token, to make sure it isn't one of the FORBIDDEN keys
                    var sbLine = new StringBuilder();
                    sbLine.Append((char)first);
                    for (;;)
                    {
                        int c = sr.Read();
                        if (c == -1 || c == '\n' || c == ' ')
                        {
                            break;
                        }

                        sbLine.Append((char)c);
                    }

                    var line = sbLine.ToString();

                    // ignore these suckers, theyre way too big for preloading. seriously, we will get out of memory errors.
                    var skip = line == HeaderKeys.SAVESTATEBINARYBASE64BLOB;

                    if (skip)
                    {
                        // skip remainder of the line
                        sr.DiscardBufferedData();
                        var stream = sr.BaseStream;
                        for (;;)
                        {
                            int c = stream.ReadByte();
                            if (c == -1 || c == '\n')
                            {
                                break;
                            }
                        }

                        // proceed to next line
                        continue;
                    }

                    var remainder = sr.ReadLine();
                    sbLine.Append(' ');
                    sbLine.Append(remainder);
                    line = sbLine.ToString();

                    if (string.IsNullOrWhiteSpace(line) || Header.ParseLineFromFile(line))
                    {
                        continue;
                    }

                    Header.Comments.Add(line);
                }
            }

            hawkFile.GetStream().Position = origStreamPosn;

            return(true);
        }
Example #9
0
        } = new List <string>();                                                   // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored!

        /// <exception cref="InvalidOperationException">internal error</exception>
        public static XmlGame Create(HawkFile f)
        {
            try
            {
                var x = new XmlDocument();
                x.Load(f.GetStream());
                var y = x.SelectSingleNode("./BizHawk-XMLGame");
                if (y == null)
                {
                    return(null);
                }

                var ret = new XmlGame
                {
                    GI =
                    {
                        System = y.Attributes["System"].Value,
                        Name   = y.Attributes["Name"].Value,
                        Status = RomStatus.Unknown
                    },
                    Xml = x
                };
                string fullPath = "";

                var n = y.SelectSingleNode("./LoadAssets");
                if (n != null)
                {
                    var hashStream    = new MemoryStream();
                    int?originalIndex = null;

                    foreach (XmlNode a in n.ChildNodes)
                    {
                        string filename = a.Attributes["FileName"].Value;
                        byte[] data;
                        if (filename[0] == '|')
                        {
                            // in same archive
                            var ai = f.FindArchiveMember(filename.Substring(1));
                            if (ai != null)
                            {
                                originalIndex ??= f.BoundIndex;
                                f.Unbind();
                                f.BindArchiveMember(ai.Value);
                                data = f.GetStream().ReadAllBytes();
                            }
                            else
                            {
                                throw new Exception($"Couldn't load XMLGame Asset \"{filename}\"");
                            }
                        }
                        else
                        {
                            // relative path
                            fullPath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? "";
                            fullPath = Path.Combine(fullPath, filename.Split('|').First());
                            try
                            {
                                using var hf = new HawkFile(fullPath);
                                if (hf.IsArchive)
                                {
                                    var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First());
                                    hf.Unbind();
                                    hf.BindArchiveMember(archiveItem);
                                    data = hf.GetStream().ReadAllBytes();

                                    filename = filename.Split('|').Skip(1).First();
                                }
                                else
                                {
                                    data = File.ReadAllBytes(fullPath.Split('|').First());
                                }
                            }
                            catch
                            {
                                throw new Exception($"Couldn't load XMLGame LoadAsset \"{filename}\"");
                            }
                        }

                        ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data));
                        ret.AssetFullPaths.Add(fullPath);
                        var sha1 = SHA1Checksum.Compute(data);
                        hashStream.Write(sha1, 0, sha1.Length);
                    }

                    ret.GI.Hash = SHA1Checksum.ComputeDigestHex(hashStream.GetBufferAsSpan());
                    hashStream.Close();
                    if (originalIndex != null)
                    {
                        f.Unbind();
                        f.BindArchiveMember((int)originalIndex);
                    }
                }
                else
                {
                    ret.GI.Hash = SHA1Checksum.Zero;
                }

                return(ret);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(ex.ToString());
            }
        }