/// <summary> /// Adds a game via the GPD /// </summary> /// <param name="xTitle"></param> /// <returns></returns> public bool AddGameViaGPD(GameGPD xTitle) { if (!ParseCheck()) return false; if (xTitle.TitleID == 0 || xTitle.TitleID == 0xFFFE07D1 || // Dash xTitle.TitleID == 0xFFFE07DE) // Avatar? return (xActive = false); foreach (TitlePlayedEntry x in xTitlesPlayed) { if (xTitle.TitleID != x.TitleID) continue; xActive = false; throw GPDExcepts.HasID; } try { string xName = xTitle.GetStringByID((long)GPDIDs.ThisTitle); if (xName == null) { xActive = false; throw GPDExcepts.NameError; } if (!xTitle.xErase()) return (xActive = false); int xsize = 0x28 + ((xName.Length + 1) * 2); int xPosition = AllocateData(xsize); if (xPosition == -1) return (xActive = false); XDBFEntry xEnt = new XDBFEntry(NameSpace.Title, xTitle.TitleID, xPosition, xsize, this); xIO.Position = xPosition + HeaderSize; xIO.Write(xTitle.TitleID); xIO.Write((uint)xTitle.xAchievements.Count); xIO.Write(xTitle.xCalcUT()); xIO.Write(xTitle.xCalcGSP()); xIO.Write(xTitle.xCalcGST()); xIO.Write(new byte[0x14]); xIO.Write(xName, StringForm.Unicode); xIO.Write((short)0); xIO.Flush(); TitlePlayedEntry z = new TitlePlayedEntry(xEnt); if (!z.LoadDetails()) return (xActive = false); xTitlesPlayed.Add(z); Setting x = xGetSetting(GPDIDs.GCardTitlesPlayed, SettingType.UInt32); if (x == null) xAddSetting((long)GPDIDs.GCardTitlesPlayed, xTitlesPlayed.Count, true, SyncType.Locale); else { uint xdata = (uint)x.Data; xdata++; x.Data = xdata; x.xUpdate(SyncType.Locale); } UpdateSync(NameSpace.Title, xTitle.TitleID, SyncType.Server); return (UpdateHeader() & !(xActive = false)); } catch { return (xActive = false); } }
int SortDate(TitlePlayedEntry Ee, TitlePlayedEntry Er) { return Ee.LastLoadedDT.CompareTo(Er.LastLoadedDT); }
/* All functions are self explanitory, here's a general structure: * Header * - Info * - XDBF Entries (Data entries) * - Free space entries (old unused data that can be reused) * Entries * * To comment everything out in GPD's would be useless and repetitive * * Achievements, Settings, and TitlesPlayed have syncs associated with them. * This is used when updating information to the servers without having to * constantly update every single item, it would be a bad system, uneffecient. * Each syncable NameSpace has a Sync Entry and an Index Record (I don't know * why they wouldn't just combine them, maybe it's a spacial issue). Sync Entry * contains the last synced entry and the next sync ID to be used when needing to * assign a sync ID. To update a sync, you just get the next SyncID, assign it to * the respected SyncPair in the IndexRecord, move it to the bottom, and increase * the next sync by one. The Xbox checks it and will sync all ID's that are * between the last sync and the next sync. One trick is you have to make sure you * order the entries in the header properly. */ internal GPD(string GPDLocale, uint xTitleID) { xActive = true; xIO = new DJsIO(GPDLocale, DJFileMode.Open, true); if (!xIO.Accessed) return; TitleID = xTitleID; xIO.IsBigEndian = true; xIO.Position = 0; if (xIO.ReadUInt32() != 0x58444246) throw GPDExcepts.IsntXDBF; xIO.Position += 4; // Version xEntryMax = xIO.ReadInt32(); xEntryCurrent = xIO.ReadInt32(); xFreeMax = xIO.ReadInt32(); xFreeCurrent = xIO.ReadInt32(); List<XDBFEntry> xEntries = new List<XDBFEntry>(); try { for (int i = 0; i < xEntryCurrent; i++) xEntries.Add(new XDBFEntry(this)); xIO.Position = (0x18 + (xEntryMax * 0x12)); for (int i = 0; i < xFreeCurrent - 1; i++) { FreeSpaceEntry x = new FreeSpaceEntry(this); xFreeEnts.Add(x); } PatchFree(); for (int i = 0; i < xEntries.Count; i++) { XDBFEntry x = xEntries[i]; switch (x.ID) { case (long)GPDIDs.IndexRecord: { RecordEntry xThisRec = new RecordEntry(x); xIndexRecords.Add(xThisRec); if (xThisRec.NS == NameSpace.Achievement && xAchievements.Count == 0) xIsInErase = true; } break; case (long)GPDIDs.SyncRecord: { SyncEntry xThisSync = new SyncEntry(x); xSyncs.Add(xThisSync); } break; default: { switch (x.NS) { case NameSpace.Nothing: xEntries.RemoveAt(i--); break; case NameSpace.Achievement: { AchievementEntry xCurrentAchievment = new AchievementEntry(x); xAchievements.Add(xCurrentAchievment); } break; case NameSpace.Image: { if (!ContainsEntry(x)) { ImageEntry xCurrentImage = new ImageEntry(x); xImages.Add(xCurrentImage); } } break; case NameSpace.Setting: { if (!ContainsEntry(x)) { Setting xThisSetting = new Setting(x); xUserSettings.Add(xThisSetting); } } break; case NameSpace.Title: { if (!ContainsEntry(x)) { TitlePlayedEntry xTitle = new TitlePlayedEntry(x); xTitlesPlayed.Add(xTitle); } } break; case NameSpace.String: { if (!ContainsEntry(x)) { StringEntry x_String = new StringEntry(x); xStrings.Add(x_String); } } break; default: xEntries.RemoveAt(i--); xEntryCurrent--; break; } } break; } } for (int i = 0; i < xUserSettings.Count; i++) { if (!xUserSettings[i].LoadDetails()) { OtherEntry xUnknown = new OtherEntry(xUserSettings[i]); xUnknownData.Add(xUnknown); xUserSettings.RemoveAt(i--); } } for (int i = 0; i < xUnknownData.Count; i++) { if (!xUnknownData[i].LoadData()) { xUnknownData.RemoveAt(i--); xEntryCurrent--; } } for (int i = 0; i < xImages.Count; i++) { if (!xImages[i].LoadImage()) { xImages.RemoveAt(i--); xEntryCurrent--; } } for (int i = 0; i < xStrings.Count; i++) { if (!xStrings[i].LoadString()) { xStrings.RemoveAt(i--); xEntryCurrent--; } } for (int i = 0; i < xIndexRecords.Count; i++) { if (!xIndexRecords[i].xLoadDetails()) { xIndexRecords.RemoveAt(i--); xEntryCurrent--; } } for (int i = 0; i < xSyncs.Count; i++) { if (!xSyncs[i].LoadSyncs()) { xSyncs.RemoveAt(i--); xEntryCurrent--; } } for (int i = 0; i < xFreeEnts.Count; i++) { if (xFreeEnts[i].Size == 0) { xFreeEnts.RemoveAt(i--); xEntryCurrent--; } } xUserSettings.Sort(sortbyid); xAchievements.Sort(sortbyid); } catch (Exception x) { xIO = null; throw x; } }
/// <summary> /// Adds a game via the GPD /// </summary> /// <param name="xTitle"></param> /// <returns></returns> public bool AddGameViaGPD(GameGPD xTitle) { if (!ParseCheck()) { return(false); } if (xTitle.TitleID == 0 || xTitle.TitleID == 0xFFFE07D1 || // Dash xTitle.TitleID == 0xFFFE07DE) // Avatar? { return(xActive = false); } foreach (TitlePlayedEntry x in xTitlesPlayed) { if (xTitle.TitleID != x.TitleID) { continue; } xActive = false; throw GPDExcepts.HasID; } try { string xName = xTitle.GetStringByID((long)GPDIDs.ThisTitle); if (xName == null) { xActive = false; throw GPDExcepts.NameError; } if (!xTitle.xErase()) { return(xActive = false); } int xsize = 0x28 + ((xName.Length + 1) * 2); int xPosition = AllocateData(xsize); if (xPosition == -1) { return(xActive = false); } XDBFEntry xEnt = new XDBFEntry(NameSpace.Title, xTitle.TitleID, xPosition, xsize, this); xIO.Position = xPosition + HeaderSize; xIO.Write(xTitle.TitleID); xIO.Write((uint)xTitle.xAchievements.Count); xIO.Write(xTitle.xCalcUT()); xIO.Write(xTitle.xCalcGSP()); xIO.Write(xTitle.xCalcGST()); xIO.Write(new byte[0x14]); xIO.Write(xName, StringForm.Unicode); xIO.Write((short)0); xIO.Flush(); TitlePlayedEntry z = new TitlePlayedEntry(xEnt); if (!z.LoadDetails()) { return(xActive = false); } xTitlesPlayed.Add(z); Setting x = xGetSetting(GPDIDs.GCardTitlesPlayed, SettingType.UInt32); if (x == null) { xAddSetting((long)GPDIDs.GCardTitlesPlayed, xTitlesPlayed.Count, true, SyncType.Locale); } else { uint xdata = (uint)x.Data; xdata++; x.Data = xdata; x.xUpdate(SyncType.Locale); } UpdateSync(NameSpace.Title, xTitle.TitleID, SyncType.Server); return(UpdateHeader() & !(xActive = false)); } catch { return(xActive = false); } }