Example #1
0
        /// <summary>
        /// Set the record to a FreeRecord
        /// </summary>
        public virtual void MarkAsFreeRecord()
        {
            var s = Ggpk.FileStream;

            s.Seek(Offset, SeekOrigin.Begin);
            var free = new FreeRecord(Length, Ggpk, 0, Offset);

            free.Write();
            var lastFree = Ggpk.FreeRecords.Last?.Value;

            if (lastFree == null)             // No FreeRecord
            {
                Ggpk.GgpkRecord.FirstFreeRecordOffset = Offset;
                s.Seek(Ggpk.GgpkRecord.Offset + 20, SeekOrigin.Begin);
                s.Write(Offset);
            }
            else
            {
                lastFree.NextFreeOffset = Offset;
                s.Seek(lastFree.Offset + 8, SeekOrigin.Begin);
                s.Write(Offset);
            }
            Ggpk.FreeRecords.AddLast(free);
        }
Example #2
0
        /// <summary>
        /// Replace the file content with a new content,
        /// and move the record to the FreeRecord with most suitable size.
        /// </summary>
        public virtual void ReplaceContent(ReadOnlySpan <byte> NewContent)
        {
            var s = Ggpk.FileStream;

            if (!Hash256.TryComputeHash(NewContent, Hash, out _))
            {
                throw new("Unable to compute hash of the content");
            }

            if (NewContent.Length == DataLength)               // Replace in situ
            {
                s.Seek(DataOffset, SeekOrigin.Begin);
                s.Write(NewContent);
            }
            else                 // Replace a FreeRecord
            {
                var oldOffset = Offset;
                MarkAsFreeRecord();
                DataLength = NewContent.Length;
                Length     = 44 + (Name.Length + 1) * 2 + DataLength;        // (8 + (Name + "\0").Length * 2 + 32 + 4) + DataLength

                LinkedListNode <FreeRecord>?bestNode = null;                 // Find the FreeRecord with most suitable size
                var currentNode = Ggpk.FreeRecords.First !;
                var space       = int.MaxValue;
                do
                {
                    if (currentNode.Value.Length == Length)
                    {
                        bestNode = currentNode;
                        space    = 0;
                        break;
                    }
                    var tmpSpace = currentNode.Value.Length - Length;
                    if (tmpSpace < space && tmpSpace >= 16)
                    {
                        bestNode = currentNode;
                        space    = tmpSpace;
                    }
                } while ((currentNode = currentNode.Next) != null);

                if (bestNode == null)
                {
                    s.Seek(0, SeekOrigin.End);                     // Write to the end of GGPK
                    Write();
                    s.Write(NewContent);
                }
                else
                {
                    FreeRecord free = bestNode.Value;
                    s.Seek(free.Offset + free.Length - Length, SeekOrigin.Begin);                     // Write to the FreeRecord
                    Write();
                    s.Write(NewContent);
                    free.Length = space;
                    if (space >= 16)                       // Update offset of FreeRecord
                    {
                        s.Seek(free.Offset, SeekOrigin.Begin);
                        s.Write(free.Length);
                    }
                    else                       // Remove the FreeRecord
                    {
                        free.Remove(bestNode);
                    }
                }

                UpdateOffset(oldOffset);                 // Update the offset of FileRecord in Parent.Entries/>
            }
            s.Flush();
        }