public static void SetChecksum(byte[] input, int offset, int len, int checksum_offset) { uint[] storedChecksums = new uint[16]; for (int i = 0; i < storedChecksums.Length; i++) { storedChecksums[i] = BigEndian.ToUInt32(input, checksum_offset + i * 4); BitConverter.GetBytes((uint)0).CopyTo(input, checksum_offset + i * 4); } uint[] checksums = new uint[16]; for (int i = 0; i < len; i += 2) { ushort val = BigEndian.ToUInt16(input, offset + i); for (int j = 0; j < 16; j++) { checksums[j] += (uint)((val >> j) & 1); } } for (int i = 0; i < checksums.Length; i++) { BigEndian.GetBytes(checksums[i]).CopyTo(input, checksum_offset + i * 4); } }
private static byte[] EncryptPBRSaveData(byte[] input) { byte[] output = new byte[input.Length]; for (int base_ofs = 0; base_ofs < SaveUtil.SIZE_G4BR; base_ofs += 0x1C0000) { Array.Copy(input, base_ofs, output, base_ofs, 8); ushort[] keys = new ushort[4]; for (int i = 0; i < keys.Length; i++) { keys[i] = BigEndian.ToUInt16(input, base_ofs + i * 2); } for (int ofs = base_ofs + 8; ofs < base_ofs + 0x1C0000; ofs += 8) { for (int i = 0; i < keys.Length; i++) { ushort val = BigEndian.ToUInt16(input, ofs + i * 2); val += keys[i]; BigEndian.GetBytes(val).CopyTo(output, ofs + i * 2); } keys = SaveUtil.AdvanceGCKeys(keys); } } return(output); }
protected override ushort CalculateChecksum() { ushort chk = 0; for (int i = 8; i < SIZE_STORED; i += 2) { chk += BigEndian.ToUInt16(Data, i); } return(chk); }
public void getPouchBigEndian(ref byte[] Data) { InventoryItem[] items = new InventoryItem[PouchDataSize]; for (int i = 0; i < items.Length; i++) { items[i] = new InventoryItem { Index = BigEndian.ToUInt16(Data, Offset + i * 4), Count = BigEndian.ToUInt16(Data, Offset + i * 4 + 2) ^ (ushort)SecurityKey }; } Items = items; }
internal static byte[] EncryptGC(byte[] input, int start, int end, ushort[] keys) { byte[] output = (byte[])input.Clone(); for (int ofs = start; ofs < end; ofs += 8) { for (int i = 0; i < keys.Length; i++) { ushort val = BigEndian.ToUInt16(input, ofs + i * 2); val += keys[i]; BigEndian.GetBytes(val).CopyTo(output, ofs + i * 2); } keys = AdvanceGCKeys(keys); } return(output); }
private static byte[] setXDChecksums(byte[] input, int subOffset0) { if (input.Length != 0x28000) { throw new ArgumentException("Input should be a slot, not the entire save binary."); } byte[] data = (byte[])input.Clone(); const int start = 0xA8; // 0x88 + 0x20 // Header Checksum int newHC = 0; for (int i = 0; i < 8; i++) { newHC += data[i]; } BigEndian.GetBytes(newHC).CopyTo(data, start + subOffset0 + 0x38); // Body Checksum new byte[16].CopyTo(data, 0x10); // Clear old Checksum Data uint[] checksum = new uint[4]; int dt = 8; for (int i = 0; i < 4; i++) { for (int j = 0; j < 0x9FF4; j += 2, dt += 2) { checksum[i] += BigEndian.ToUInt16(data, dt); } } ushort[] newchks = new ushort[8]; for (int i = 0; i < 4; i++) { newchks[i * 2] = (ushort)(checksum[i] >> 16); newchks[i * 2 + 1] = (ushort)checksum[i]; } Array.Reverse(newchks); for (int i = 0; i < newchks.Length; i++) { BigEndian.GetBytes(newchks[i]).CopyTo(data, 0x10 + 2 * i); } return(data); }
public override byte[] Write(bool DSV) { // Set Memo Back StrategyMemo.FinalData.CopyTo(Data, Memo); ShadowInfo.FinalData.CopyTo(Data, Shadow); setChecksums(); // Get updated save slot data ushort[] keys = new ushort[4]; for (int i = 0; i < keys.Length; i++) { keys[i] = BigEndian.ToUInt16(Data, 8 + i * 2); } byte[] newSAV = SaveUtil.EncryptGC(Data, 0x10, 0x27FD8, keys); // Put save slot back in original save data byte[] newFile = (byte[])OriginalData.Clone(); Array.Copy(newSAV, 0, newFile, SLOT_START + SaveIndex * SLOT_SIZE, newSAV.Length); return(Header.Concat(newFile).ToArray()); }
public SAV3XD(byte[] data = null) { Data = data == null ? new byte[SaveUtil.SIZE_G3XD] : (byte[])data.Clone(); BAK = (byte[])Data.Clone(); Exportable = !Data.SequenceEqual(new byte[Data.Length]); if (SaveUtil.getIsG3XDSAV(Data) != GameVersion.XD) { return; } OriginalData = (byte[])Data.Clone(); // Scan all 3 save slots for the highest counter for (int i = 0; i < SLOT_COUNT; i++) { int slotOffset = SLOT_START + i * SLOT_SIZE; int SaveCounter = BigEndian.ToInt32(Data, slotOffset + 4); if (SaveCounter <= SaveCount) { continue; } SaveCount = SaveCounter; SaveIndex = i; } // Decrypt most recent save slot { byte[] slot = new byte[SLOT_SIZE]; int slotOffset = SLOT_START + SaveIndex * SLOT_SIZE; Array.Copy(Data, slotOffset, slot, 0, slot.Length); ushort[] keys = new ushort[4]; for (int i = 0; i < keys.Length; i++) { keys[i] = BigEndian.ToUInt16(slot, 8 + i * 2); } // Decrypt Slot Data = SaveUtil.DecryptGC(slot, 0x00010, 0x27FD8, keys); } // Get Offset Info ushort[] subLength = new ushort[16]; for (int i = 0; i < 16; i++) { subLength[i] = BigEndian.ToUInt16(Data, 0x20 + 2 * i); subOffsets[i] = BigEndian.ToUInt16(Data, 0x40 + 4 * i) | BigEndian.ToUInt16(Data, 0x40 + 4 * i + 2) << 16; } // Offsets are displaced by the 0xA8 savedata region Trainer1 = subOffsets[1] + 0xA8; Party = Trainer1 + 0x30; Box = subOffsets[2] + 0xA8; Daycare = subOffsets[4] + 0xA8; Memo = subOffsets[5] + 0xA8; Shadow = subOffsets[7] + 0xA8; // Purifier = subOffsets[14] + 0xA8; StrategyMemo = new StrategyMemo(Data, Memo, xd: true); ShadowInfo = new ShadowInfoTableXD(Data.Skip(Shadow).Take(subLength[7]).ToArray()); OFS_PouchHeldItem = Trainer1 + 0x4C8; OFS_PouchKeyItem = Trainer1 + 0x540; OFS_PouchBalls = Trainer1 + 0x5EC; OFS_PouchTMHM = Trainer1 + 0x62C; OFS_PouchBerry = Trainer1 + 0x72C; OFS_PouchCologne = Trainer1 + 0x7E4; OFS_PouchDisc = Trainer1 + 0x7F0; LegalItems = Legal.Pouch_Items_XD; LegalKeyItems = Legal.Pouch_Key_XD; LegalBalls = Legal.Pouch_Ball_RS; LegalTMHMs = Legal.Pouch_TM_RS; // not HMs LegalBerries = Legal.Pouch_Berries_RS; LegalCologne = Legal.Pouch_Cologne_CXD; LegalDisc = Legal.Pouch_Disc_XD; Personal = PersonalTable.RS; HeldItems = Legal.HeldItems_XD; if (!Exportable) { resetBoxes(); } // Since PartyCount is not stored in the save file, // Count up how many party slots are active. for (int i = 0; i < 6; i++) { if (getPartySlot(getPartyOffset(i)).Species != 0) { PartyCount++; } } }