Пример #1
0
        public static void addSupercardDS2PluginInfo(ROMInfo info, ROMFile file)
        {
            info.addInfo("Platform", "Supercard DSTwo");
            string iconFilename = System.IO.Path.ChangeExtension(file.name, "bmp");
            //The icon is actually pointed to in the .ini file, but it's in a native DS format (starts with fat1:/) so it won't be of any use unless running on an actual DSTwo. Luckily, the filename is always the same as the .plg but with a .bmp extension; and this is the kind of convention that nobody would dare break
            var icon = Image.FromStream(file.getSiblingFile(iconFilename));

            info.addInfo("Icon", icon);

            string iniFilename = System.IO.Path.ChangeExtension(file.name, "ini");

            using (var sr = new System.IO.StreamReader(file.getSiblingFile(iniFilename))) {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    if (line == null)
                    {
                        break;
                    }

                    if (line.ToLowerInvariant().StartsWith("name="))
                    {
                        //Once again, not really internal. I kinda want to rename this column globally, it's already kinda wordy and a mouthful and I don't like that
                        info.addInfo("Internal name", line.Split('=')[1]);
                        break;
                    }
                }
            }
        }
Пример #2
0
        public static void parseXEX(ROMInfo info, ROMFile file)
        {
            if (file.hasSiblingFile("ArcadeInfo.xml"))
            {
                parseArcadeInfo(info, file, file.getSiblingFile("ArcadeInfo.xml"));
            }

            var s = file.stream;

            s.Position = 4;
            uint flags = (uint)s.readIntBE();

            parseXEXFlags(info, flags);

            s.Position = 0x14;
            uint headerCount = (uint)s.readIntBE();

            for (uint i = 0; i < headerCount; ++i)
            {
                uint   headerID   = (uint)s.readIntBE();
                uint   headerSize = headerID & 0xff;
                byte[] headerData = s.read(4);

                if (headerSize == 0 || headerSize == 1)
                {
                    addXEXInfo(info, headerID, headerData);
                }
                else
                {
                    long pos = s.Position;
                    try {
                        uint offset = bytesToUintBE(headerData);
                        s.Position = offset;

                        byte[] data;
                        if (headerSize == 0xff)
                        {
                            headerSize = (uint)s.readIntBE() - 4;
                        }
                        else
                        {
                            headerSize = headerSize * 4;
                        }
                        data = s.read((int)headerSize);

                        addXEXInfo(info, headerID, data);
                    } finally {
                        s.Position = pos;
                    }
                }
            }
        }
Пример #3
0
 public static void addRPXInfo(ROMInfo info, ROMFile file)
 {
     //Mmmmm not sure I like this usage of .. but uhh I guess it works and it's what I have to do
     foreach (var kv in imagePaths)
     {
         if (file.hasSiblingFile(kv.Key))
         {
             //var image = Image.FromStream(file.getSiblingFile(kv.Key));
             //info.addInfo(kv.Value, image);
             //TODO: Oh, I guess C# doesn't natively support TGA. Whoops. I thought it did. I guess I'll have to do that myself.
         }
     }
     //TODO: Perhaps add bootMovie.h264 and bootSound.btsnd... one day. I mean, they'd obviously be a bit complicated to decode. Unless there's some crossplatform H264 decoder for the former at least.
     if (file.hasSiblingFile("../meta/meta.xml"))
     {
         var doc = XDocument.Load(file.getSiblingFile("../meta/meta.xml")).Element("menu");
         parseMetaXML(info, doc);
     }
 }
Пример #4
0
        public static void parse3DSX(ROMInfo info, ROMFile file)
        {
            WrappedInputStream s = file.stream;

            s.Position = 4;
            short headerSize        = s.readShortLE();
            bool  hasExtendedHeader = headerSize > 32;

            info.addInfo("Header size", headerSize, ROMInfo.FormatMode.SIZE);

            //meh..... don't really care about the rest of the 3dsx header, it's basically just a boneless .elf
            bool lookForSMDHFile = true;

            if (hasExtendedHeader)
            {
                s.Position = 32;
                uint smdhOffset = (uint)s.readIntLE();
                uint smdhSize   = (uint)s.readIntLE();
                info.addInfo("SMDH offset", smdhOffset, ROMInfo.FormatMode.HEX);
                info.addInfo("SMDH size", smdhSize, ROMInfo.FormatMode.SIZE);

                if (smdhSize > 0)
                {
                    lookForSMDHFile = false;
                    parseSMDH(info, s, null, smdhOffset);
                }
            }

            if (lookForSMDHFile)
            {
                string smdhName = Path.ChangeExtension(file.name, "smdh");
                if (file.hasSiblingFile(smdhName))
                {
                    var smdh = file.getSiblingFile(smdhName);
                    parseSMDH(info, smdh, null);
                }
            }
        }
Пример #5
0
        public static void parseTitleInfo(ROMInfo info, ROMFile file, XElement titleInfo)
        {
            var    localeAttrib = titleInfo.Attribute("locale");
            string prefix       = String.Empty;

            if (localeAttrib != null)
            {
                try {
                    //We use .Parent here to get just the language, and not the country specific to that language, so that it's consistent with other multi-language columns in other handlers
                    prefix = System.Globalization.CultureInfo.GetCultureInfoByIetfLanguageTag(localeAttrib.Value).Parent.DisplayName;
                } catch (System.Globalization.CultureNotFoundException) {
                    prefix = localeAttrib.Value;
                }
            }

            //ID = some numeric value? For example, Banjo-Kazooie is 1480657236 and Banjo-Tooie is 1480657237
            //This might actually just be the same as the Title ID in the .xex, if you convert that number to a byte array with big endian, and then as usual it's 2-char manufacturer and 2-byte something else

            var nameAttrib = titleInfo.Attribute("Name");

            if (nameAttrib != null)
            {
                info.addInfo(combinePrefix(prefix, "Name"), nameAttrib.Value);
            }

            //Path is the name of the xex file, but we already know where that is so don't mind that (although is there an XBLA game with this ArcadeInfo.xml file and multiple .xex files, and the main one this ArcadeInfo.xml is applicable is the one referred to and not the other ones? Probably not)

            var iconAttrib = titleInfo.Attribute("ImagePath");

            if (iconAttrib != null)
            {
                string iconName = iconAttrib.Value;
                if (file.hasSiblingFile(iconName))
                {
                    var icon = System.Drawing.Image.FromStream(file.getSiblingFile(iconName));
                    info.addInfo(combinePrefix(prefix, "Icon"), icon);
                }
            }

            //MaxCred = 200 but I don't know what that does. Credits? You don't have credits in Banjo-Kazooie, kid

            var minPlayersAttrib = titleInfo.Attribute("MinPlayers");

            if (minPlayersAttrib != null)
            {
                info.addInfo(combinePrefix(prefix, "Minimum players"), int.Parse(minPlayersAttrib.Value));
            }

            var maxPlayersAttrib = titleInfo.Attribute("MaxPlayers");

            if (maxPlayersAttrib != null)
            {
                info.addInfo(combinePrefix(prefix, "Maximum players"), int.Parse(maxPlayersAttrib.Value));
            }

            var scoreNameAttrib = titleInfo.Attribute("ScoreName");

            if (scoreNameAttrib != null)
            {
                //Used for leaderboards, for example for Banjo-Kazooie this is "Jiggies" as it compares how many jiggies you've collected compared to your friends
                info.addInfo(combinePrefix(prefix, "Scoring name"), scoreNameAttrib.Value);
            }

            var descriptionElement = titleInfo.Element("Description");

            if (descriptionElement != null)
            {
                info.addInfo(combinePrefix(prefix, "Description"), descriptionElement.Value);
            }

            //Multiple AchievementInfo elements, which have no content and only ID attributes (some unique number for each AchievementInfo element) and an ImagePath pointing to an icon in this directory that represents the achievement

            //Leaderboard I don't quite understand, it's like <Leaderboard view="12" column="2" type="int" sort="Descending" />

            int i = 1;

            foreach (var genreElement in titleInfo.Elements("Genre"))
            {
                var genreAttrib = genreElement.Attribute("genreId");
                if (genreAttrib != null)
                {
                    //TODO: How are genres encoded into numbers like this? They don't seem to be consistent with what shows up in Game Details on an actual console, unless I need to redump my stuff because it's been updated or something
                    //So as you can see from the wiki page it's a bit messed up, there are games of the same genre internally that don't display as the same genre, or there's games that display as the same genre but aren't the same internally. Either there's been updates and if I dump them again it'll start making sense, or the Xbox 360 just goes to Xbox Live to get genre information and ignores whatever's here anyway.
                    //Having said that, there seems to be a few values which we can deduce as most likely being correct
                    info.addInfo(combinePrefix(prefix, i == 1 ? "Genre" : "Genre " + i), genreAttrib.Value, GENRES);
                }
                ++i;
            }

            var parentalControl = titleInfo.Element("Parental-Control");

            if (parentalControl != null)
            {
                foreach (var system in parentalControl.Elements("System"))
                {
                    info.addInfo(combinePrefix(prefix, system.Attribute("id").Value + " rating descriptor"), system.Value);
                    var ratingImageAttribute = system.Attribute("ImagePath");
                    if (ratingImageAttribute != null)
                    {
                        string ratingImagePath = ratingImageAttribute.Value;
                        if (file.hasSiblingFile(ratingImagePath))
                        {
                            var ratingImage = System.Drawing.Image.FromStream(file.getSiblingFile(ratingImagePath));
                            info.addInfo(combinePrefix(prefix, system.Attribute("id").Value + " rating image"), ratingImage);;
                        }
                    }
                }
            }
        }
Пример #6
0
        public override void addROMInfo(ROMInfo info, ROMFile file)
        {
            //TODO: Read .elf header
            info.addInfo("Platform", name);
            if (file.hasSiblingFile("icon.png"))
            {
                var iconStream = file.getSiblingFile("icon.png");
                var icon       = Image.FromStream(iconStream);
                info.addInfo("Icon", icon);
            }

            if (file.hasSiblingFile("meta.xml"))
            {
                var metaXML = XDocument.Load(file.getSiblingFile("meta.xml"));
                //TODO: Some apps have invalid XML according to this, but they show up in the HBC just fine... and some don't and really do have broken XML and we should catch the exception in that case

                var app = metaXML.Element("app");
                //<app> has a version attribute, but it is always "1"
                string name  = app.Element("name")?.Value;
                string coder = app.Element("coder")?.Value;
                if (coder == null)
                {
                    coder = app.Element("author")?.Value;
                }
                string version          = app.Element("version")?.Value;
                string releaseDate      = app.Element("release_date")?.Value;
                string shortDescription = app.Element("short_description")?.Value;
                string longDescription  = app.Element("long_description")?.Value;
                string arguments        = app.Element("arguments")?.Value;

                //Note that in the HBC source release, these two things seem to be interpreted exactly the same way
                bool ahbAccess   = app.Element("ahb_access") != null;
                bool noIOSReload = app.Element("no_ios_reload") != null;

                if (name != null)
                {
                    //Well, we call it an internal name for consistency. But is that really accurate? It is by definition external, after all; should I just rename it to "Name"?
                    info.addInfo("Internal name", name);
                }
                if (coder != null)
                {
                    //As with Master System homebrew headers, should I call this "Author" and have a distinction with that and "Manufacturer" or should those be combined into a thing which is cleverly worded enough to be both?
                    info.addInfo("Author", coder);
                }
                if (version != null)
                {
                    info.addInfo("Version", version);
                }
                if (releaseDate != null)
                {
                    //Officially, only the last one is correct. But you don't actually expect people to follow standards, do you?
                    //There are also some where it's text with the month name not even spelled correctly, some where I don't even know what they were trying to do because any conceivable format results in them having a month above 12 or hour above 23 or something like that, and some are ambiguous between dd/mm/yyyy and the wrong date format, and why are you people like this?
                    string[] formats = { "yyyyMMdd", "yyyyMMddHHmm", "yyyyMMdd000", "yyyyMMdd00000", "yyyy-MM-dd", "yyyyMMddHHmmss" };
                    if (DateTime.TryParseExact(releaseDate, formats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime date))
                    {
                        info.addInfo("Date", date);
                        info.addInfo("Year", date.Year);
                        info.addInfo("Month", DateTimeFormatInfo.CurrentInfo.GetMonthName(date.Month));
                        info.addInfo("Day", date.Day);
                    }
                    else
                    {
                        info.addInfo("Date", releaseDate);
                    }
                }
                if (shortDescription != null)
                {
                    info.addInfo("Description", shortDescription);
                }
                if (longDescription != null)
                {
                    //Yeah you don't want this in a table
                    info.addInfo("Long description", longDescription.Replace("\n", Environment.NewLine), true);
                }
                if (arguments != null)
                {
                    info.addInfo("Arguments", arguments);
                }
                info.addInfo("AHB access", ahbAccess);
                info.addInfo("No IOS reload", noIOSReload);
            }
        }