Example #1
0
        private int[] AllocateBlocks(int count)
        {
            if (count <= 0)
            {
                return(new int[0]);
            }

            var freeCount = UnallocatedHashEntries.Count > count ? count : UnallocatedHashEntries.Count;
            var res       = new List <int>();

            if (freeCount > 0)
            {
                res.AddRange(UnallocatedHashEntries.Take(freeCount));
                UnallocatedHashEntries.RemoveRange(0, freeCount);

                var lastTable = TopLevel == 0 ? TopTable : TopTable.Tables[TopTable.EntryCount - 1];
                var lastEntry = lastTable.Entries.FirstOrDefault(e => e.Block == res.Last());
                if (lastEntry != null)
                {
                    var index = lastTable.Entries.ToList().IndexOf(lastEntry);
                    lastTable.EntryCount = index + 1;
                    if (res.Last() + 1 > VolumeDescriptor.AllocatedBlockCount)
                    {
                        VolumeDescriptor.AllocatedBlockCount = res.Last() + 1;
                        Binary.EnsureBinarySize(GetRealAddressOfBlock(VolumeDescriptor.AllocatedBlockCount));
                    }
                }
            }
            var toAlloc = count - freeCount;

            if (toAlloc > 0)
            {
                switch (TopLevel)
                {
                case 0:
                    throw new NotImplementedException("Table upgrade from lvl 0 to 1 needed!");

                case 1:
                    if (TopTable.EntryCount == 0xAA)
                    {
                        throw new NotImplementedException("Table upgrade from lvl 1 to 2 needed!");
                    }

                    //allocate a new table
                    var table      = GetLevelNHashTable(TopTable.EntryCount, 0);
                    var tableEntry = TopTable.Entries[TopTable.EntryCount++];
                    tableEntry.RealBlock = table.Block;
                    tableEntry.Status    = BlockStatus.Allocated;
                    TopTable.Tables.Add(table);

                    res.AddRange(AllocateBlocks(toAlloc));
                    break;

                default:
                    throw new NotSupportedException("Unsupported level" + TopLevel);
                }
            }
            return(res.ToArray());
        }
Example #2
0
        private void RemoveFile(FileEntry parent, FileEntry fileEntry)
        {
            var block = fileEntry.StartingBlockNum;

            for (var i = 0; i < fileEntry.BlocksForFile; i++)
            {
                var he = GetHashEntry(block);
                he.Status = BlockStatus.PreviouslyAllocated;
                if (UnallocatedHashEntries.Contains(block))
                {
                    throw new Exception("qwe");
                }
                UnallocatedHashEntries.Add(block);
                block = he.NextBlock;
            }
            fileEntry.BlocksForFile = 0;
            fileEntry.Name          = string.Empty;
            parent.Files.Remove(fileEntry);
        }
Example #3
0
        public void ReplaceFile(FileEntry fileEntry, byte[] content)
        {
            if (fileEntry.IsDirectory)
            {
                throw new NotSupportedException("Directories doesn't have content!");
            }

            var remaining = content.Length;

            var allocatedBlockCount = fileEntry.BlocksForFile;
            var newBlockCount       = (content.Length + 0xFFF) / 0x1000;
            var blocks = AllocateBlocks(newBlockCount - allocatedBlockCount);
            var block  = fileEntry.StartingBlockNum;

            if (allocatedBlockCount == 0)
            {
                block = blocks[0];
                fileEntry.StartingBlockNum = blocks[0];
            }
            var consecutive = true;

            for (var i = 0; i < newBlockCount; i++)
            {
                var pos  = GetRealAddressOfBlock(block);
                var size = remaining > 0x1000 ? 0x1000 : remaining;
                remaining -= size;
                var buffer = new byte[0x1000];
                Buffer.BlockCopy(content, i * 0x1000, buffer, 0, size);
                Binary.WriteBytes(pos, buffer, 0, 0x1000);

                var he = GetHashEntry(block);
                if (i < allocatedBlockCount - 1)
                {
                    he.Status = BlockStatus.Allocated;
                    if (he.NextBlock != block + 1)
                    {
                        consecutive = false;
                    }
                    block = he.NextBlock;
                }
                else if (i < newBlockCount - 1)
                {
                    he.Status    = BlockStatus.NewlyAllocated;
                    block        = blocks[i - allocatedBlockCount + 1];
                    he.NextBlock = block;
                    if (he.NextBlock != he.Block + 1)
                    {
                        consecutive = false;
                    }
                }
                else
                {
                    he.Status    = BlockStatus.NewlyAllocated;
                    he.NextBlock = 0xFFFFFF;
                }
            }

            for (var i = newBlockCount; i < allocatedBlockCount; i++)
            {
                var he = GetHashEntry(block);
                if (UnallocatedHashEntries.Contains(block))
                {
                    throw new Exception("qwe");
                }
                UnallocatedHashEntries.Add(block);
                he.Status    = BlockStatus.PreviouslyAllocated;
                block        = he.NextBlock;
                he.NextBlock = 0xFFFFFF;
            }

            fileEntry.FileSize             = content.Length;
            fileEntry.BlocksForFile        = newBlockCount;
            fileEntry.BlocksForFileCopy    = newBlockCount;
            fileEntry.BlocksAreConsecutive = consecutive;
        }
Example #4
0
        public void MergeWith(StfsPackage otherProfile)
        {
            if (!IsModified)
            {
                SwitchTables();
            }

            var count = otherProfile.ProfileInfo.TitlesPlayed.Count;

            NotifyContentCountDetermined(count);

            var otherPec     = otherProfile.ExtractPec();
            var pecFileEntry = GetFileEntry("PEC");
            var pec          = ExtractPec();

            //HACK horizon
            int?newBlock = AllocateBlocks(1)[0];

            foreach (var title in otherProfile.ProfileInfo.TitlesPlayed)
            {
                var watch = new Stopwatch();
                watch.Start();
                var name              = title.TitleCode + ".gpd";
                var otherGame         = otherProfile.GetGameFile(name, true);
                var otherAvatarAwards = otherPec.GetGameFile(name, true);

                var fileEntry = GetFileEntry(name, true);
                if (fileEntry != null)
                {
                    var titleEntry = ProfileInfo.TitlesPlayed.FirstOrDefault(t => t.TitleCode == title.TitleCode);
                    if (titleEntry != null)
                    {
                        //Title already exists in target, merge is necessary
                        var game = GetGameFile(fileEntry, true);
                        if (game.MergeWith(otherGame))
                        {
                            RebuildGame(game);
                        }

                        if (otherAvatarAwards != null)
                        {
                            var avatarAwards = pec.GetGameFile(name, true);
                            if (avatarAwards != null)
                            {
                                if (avatarAwards.MergeWith(otherAvatarAwards))
                                {
                                    avatarAwards.Rebuild();
                                    var pecGpdEntry = pec.GetFileEntry(name);
                                    pec.ReplaceFile(pecGpdEntry, avatarAwards);
                                }
                            }
                            else
                            {
                                pec.AddFile(name, otherAvatarAwards.Binary.ReadAll());
                            }
                        }
                    }
                    else
                    {
                        throw new Exception("Title doesn't exists, but the gpd file does");
                        //Title doesn't exists, but the gpd file does, we just replace that

                        //var otherBinary = otherGame.Binary.ReadAll();
                        //ReplaceFile(fileEntry, otherBinary);
                        //var tid = title.TitleId.ToArray();
                        //Array.Reverse(tid);
                        //var id = BitConverter.ToUInt32(tid, 0);
                        //ProfileInfo.AddNewEntry<TitleEntry>(EntryType.Title, title.AllBytes, id);
                        //info = "added";
                    }
                }
                else
                {
                    if (otherAvatarAwards != null)
                    {
                        pec.AddFile(name, otherAvatarAwards.Binary.ReadAll());
                    }

                    if (otherGame != null)
                    {
                        //Add gpd and title
                        var otherBinary = otherGame.Binary.ReadAll();

                        //File.WriteAllBytes(@"d:\NTX-CNT\Contour\Resources\mergeable\aktualis\q\" + i + "_" + name, otherBinary);

                        fileEntry = AddFile(name, otherBinary);
                        CreateGameFileModel(fileEntry, otherBinary, true);

                        var tid = title.TitleId.ToArray();
                        Array.Reverse(tid);
                        var id = BitConverter.ToUInt32(tid, 0);
                        ProfileInfo.AddNewEntry <TitleEntry>(EntryType.Title, title.AllBytes, id);
                    }
                }
                watch.Stop();
                //LogHelper.NotifyStatusBarChange(++i);
                //LogHelper.NotifyStatusBarText(string.Format("{0}/{1} {2} merged", i, count, title.TitleName));
            }

            //LogHelper.NotifyStatusBarText("Rebuilding profile...");
            foreach (var title in ProfileInfo.TitlesPlayed)
            {
                var name = title.TitleCode + ".gpd";
                var game = GetGameFile(name, true);
                title.LastAchievementEarnedOn = game.AchievementCount > 0 ? game.Achievements.Max(a => a.UnlockTime) : DateTime.MinValue;
            }

            //HACK: Horizon
            var previous = 0;
            var block    = VolumeDescriptor.FileTableBlockNum;

            for (var k = 0; k < VolumeDescriptor.FileTableBlockCount - 1; k++)
            {
                var hek = GetHashEntry(block);
                previous = block;
                block    = hek.NextBlock;
            }
            Binary.WriteBytes(GetRealAddressOfBlock(newBlock.Value), Binary.ReadBytes(GetRealAddressOfBlock(block), 0x1000), 0, 0x1000);
            var he = GetHashEntry(block);

            he.Status = BlockStatus.PreviouslyAllocated;
            he        = GetHashEntry(newBlock.Value);
            he.Status = BlockStatus.NewlyAllocated;
            UnallocatedHashEntries.Add(block);
            GetHashEntry(previous).NextBlock = newBlock.Value;

            ProfileInfo.Recalculate();
            ProfileInfo.Rebuild();
            ReplaceFile(ProfileEntry, ProfileInfo);

            pec.Rehash();
            pec.Resign();
            ReplaceFile(pecFileEntry, pec.Binary.ReadAll());
        }
Example #5
0
        public HashTable GetLevelNHashTable(int index, int level)
        {
            if (level < 0 || level > TopLevel)
            {
                throw new ArgumentException("Invalid level: " + level);
            }

            var x       = TopLevel != level ? 0xAA : 1;
            var current = ComputeLevelNBackingHashBlockNumber(index * x, level);
            int entryCount;

            if (level == TopLevel)
            {
                if (VolumeDescriptor.BlockSeparation == 2)
                {
                    current++;
                }

                entryCount = VolumeDescriptor.AllocatedBlockCount;
                if (entryCount >= 0xAA)
                {
                    entryCount = (entryCount + 0xA9) / 0xAA;
                }
            }
            else if (level + 1 == TopLevel)
            {
                var entry = TopTable.Entries[index];
                if (entry.Status == BlockStatus.NewlyAllocated || entry.Status == BlockStatus.PreviouslyAllocated)
                {
                    current++;
                }

                // calculate the number of entries in the requested table
                entryCount = index + 1 == TopTable.EntryCount
                                 ? VolumeDescriptor.AllocatedBlockCount % 0xAA
                                 : index == TopTable.EntryCount ? 0 : 0xAA;
            }
            else
            {
                throw new NotSupportedException();
            }

            var currentHashAddress = (current << 0xC) + FirstHashTableAddress;

            Binary.EnsureBinarySize(currentHashAddress + 0x1000);
            var table = ModelFactory.GetModel <HashTable>(Binary, currentHashAddress);

            table.Block      = current;
            table.EntryCount = entryCount;

            for (var j = 0; j < 0xAA; j++)
            {
                var entry = table.Entries[j];
                entry.Block     = index * 0xAA + j;
                entry.RealBlock = GetRealBlockNum(entry.Block.Value);
            }
            if (level == 0)
            {
                var unallocatedEntries =
                    table.Entries.Where(
                        e => e.Status == BlockStatus.Unallocated || e.Status == BlockStatus.PreviouslyAllocated);
                UnallocatedHashEntries.AddRange(unallocatedEntries.Select(e => e.Block.Value));
            }

            return(table);
        }