Example #1
0
        /// <summary>
        /// Check the updates PSN servers and insert/update the relevant DB records.
        /// </summary>
        /// <param name="db">The database context.</param>
        /// <param name="title_id">The TITLE_ID to search updates for.</param>
        public static void Check(Database db, string title_id)
        {
            var document = Update.GetUpdateData(title_id);

            if (document == null)
            {
                return;
            }

            TitlePatch patch = DeserializeFromXML <TitlePatch>(document);

            if (patch.Tag != null)
            {
                foreach (var update_pkg in Nullable(patch.Tag.Packages))
                {
                    Update update = new Update
                    {
                        CONTENT_ID = update_pkg.ContentId,
                        VERSION    = GetVersionFromString(update_pkg.Version),
                        TYPE       = db.Type[update_pkg.Type ?? "cumulative"],
                        URL        = update_pkg.Url,
                        Size       = update_pkg.Size,
                        Sha1Sum    = HexStringToByteArray(update_pkg.Sha1Sum),
                        SysVer     = GetVersionFromBcd(update_pkg.SysVer),
                    };

                    var app = db.Apps.Where(x => x.CONTENT_ID == update.CONTENT_ID).FirstOrDefault();
                    if (app == null)
                    {
                        app = new App
                        {
                            CONTENT_ID = update.CONTENT_ID,
                            TITLE_ID   = update.CONTENT_ID.Substring(7, 9),
                            NAME       = document.Descendants("title").FirstOrDefault().Value
                        };
                        Console.WriteLine($"[NOTE] Adding new App {app.CONTENT_ID}: {app.NAME}");
                        db.Apps.Add(app);
                        db.SaveChanges();
                    }

                    var pkg = db.Pkgs.Where(x => x.URL == update.URL).FirstOrDefault();
                    if (pkg == null)
                    {
                        pkg = Pkg.CreatePkg(update.URL);
                        if (pkg == null)
                        {
                            continue;
                        }
                        db.Pkgs.Add(pkg);
                        db.SaveChanges();
                    }
                    update.PKG_ID = pkg.ID;
                    update.Upsert(db, true);

                    if (update_pkg.HybridPackage != null)
                    {
                        // Hybrid packages are derived from parent
                        update.CONTENT_ID = update_pkg.HybridPackage.ContentId;
                        update.TYPE       = db.Type["hybrid"];
                        update.URL        = update_pkg.HybridPackage.Url;
                        update.Size       = update_pkg.HybridPackage.Size;
                        update.Sha1Sum    = HexStringToByteArray(update_pkg.HybridPackage.Sha1Sum);

                        pkg = db.Pkgs.Where(x => x.URL == update.URL).FirstOrDefault();
                        if (pkg == null)
                        {
                            pkg = Pkg.CreatePkg(update.URL);
                            db.Pkgs.Add(pkg);
                            db.SaveChanges();
                        }
                        update.PKG_ID = pkg.ID;
                        update.Upsert(db, true);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Create a new Pkg object from a PKG URL.
        /// </summary>
        /// <param name="url">The source URL.</param>
        /// <returns>A new Pkg instance, or null on error.</returns>
        public static Pkg CreatePkg(string url)
        {
            int i;

            for (i = 0; i < pkg_start.Count; i++)
            {
                if (url.StartsWith(pkg_start[i]))
                {
                    break;
                }
            }
            if (i >= pkg_start.Count)
            {
                Console.Error.WriteLine($"[ERROR] '{url}' does not match known PSN URLs");
                return(null);
            }
            // Trim extra data after pkg (such as "?country=...")
            url = url.Split('?').First();
            if (!url.EndsWith(".pkg"))
            {
                Console.Error.WriteLine($"[ERROR] '{url}' does not end with '.pkg'");
                return(null);
            }

            byte[] pkg_header = GetPkgData(url, 0, (UInt32)(PKG_HEADER_SIZE + PKG_HEADER_EXT_SIZE));
            if (pkg_header == null)
            {
                Console.Error.WriteLine($"[ERROR] Could not read PKG header from '{url}'");
                return(null);
            }
            if (!MemCmp(pkg_header, pkg_magic, 0))
            {
                Console.WriteLine("[ERROR] '{url}' is not a PKG file");
                return(null);
            }

            var pkg = new Pkg {
                URL        = url,
                CONTENT_ID = GetContentIdFromPkg(url, pkg_header)
            };

            if (!App.ValidateContentID(pkg.CONTENT_ID))
            {
                Console.WriteLine("[ERROR] Could not get a valid CONTENT_ID from PKG URL '{url}'");
                return(null);
            }

            // http://www.psdevwiki.com/ps3/PKG_files
            UInt32 info_offset = GetBe32(pkg_header, 0x08);
            UInt32 info_count  = GetBe32(pkg_header, 0x0c);
            UInt32 item_count  = GetBe32(pkg_header, 0x14);

            pkg.SIZE = GetBe64(pkg_header, 0x18);
            UInt64 data_offset = GetBe64(pkg_header, 0x20);

            byte[] iv       = MemCpy(pkg_header, 0x70, 0x10);
            int    key_type = pkg_header[0xe7] & 0x07;

            byte[] pkg_info = GetPkgData(url, info_offset, (UInt32)(data_offset - info_offset));
            if (pkg_info != null)
            {
                byte[] sfo_data = null;
                UInt32 type, size;
                string default_category = null;
                for (int count = 0, pos = 0; (count < info_count) && (pos < pkg_info.Length); count++, pos += (int)size)
                {
                    type = GetBe32(pkg_info, pos);
                    size = GetBe32(pkg_info, pos + 4);
                    pos += 8;
                    if (type == 0x02)
                    {
                        content_type.TryGetValue(GetBe32(pkg_info, pos), out default_category);
                    }
                    else if (type == 0x0E)
                    {
                        UInt32 sfo_pos  = GetBe32(pkg_info, pos);
                        UInt32 sfo_size = GetBe32(pkg_info, pos + 4);
                        // Avoid a server round trip, as the SFO should be part of pkg_info
                        if ((sfo_pos >= info_offset) && (sfo_pos - info_offset + sfo_size <= pkg_info.Length))
                        {
                            sfo_data = MemCpy(pkg_info, (int)(sfo_pos - info_offset), (int)sfo_size);
                        }
                        else
                        {
                            sfo_data = GetPkgData(url, sfo_pos, sfo_size);
                        }
                        break;
                    }
                }
                if (sfo_data != null)
                {
                    var sfo = new Sfo(sfo_data);
                    pkg.APP_VER  = sfo.AppVer;
                    pkg.CATEGORY = sfo.Category ?? default_category;
                    pkg.C_DATE   = sfo.CDate;
                    pkg.SYS_VER  = sfo.SysVer;
                }
                else
                {
                    pkg.CATEGORY = default_category;
                }
            }
            pkg.SHA1   = ByteArrayToHexString(GetPkgSha1(url));
            pkg.V_DATE = ((UInt32)DateTime.Now.Year) * 10000
                         + ((UInt32)DateTime.Now.Month) * 100
                         + ((UInt32)DateTime.Now.Day);
            return(pkg);
        }