/// <summary> /// Set the record to a FreeRecord /// </summary> public virtual void MarkAsFreeRecord() { var bw = ggpkContainer.Writer; bw.BaseStream.Seek(Offset, SeekOrigin.Begin); var free = new FreeRecord(Length, ggpkContainer, 0, Offset); free.Write(); var lastFree = ggpkContainer.LinkedFreeRecords.Last?.Value; if (lastFree == null) // No FreeRecord { ggpkContainer.ggpkRecord.FirstFreeRecordOffset = Offset; ggpkContainer.fileStream.Seek(ggpkContainer.ggpkRecord.Offset + 20, SeekOrigin.Begin); ggpkContainer.Writer.Write(Offset); } else { lastFree.NextFreeOffset = Offset; ggpkContainer.fileStream.Seek(lastFree.Offset + 8, SeekOrigin.Begin); ggpkContainer.Writer.Write(Offset); } ggpkContainer.LinkedFreeRecords.AddLast(free); }
/// <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(byte[] NewContent) { var bw = ggpkContainer.Writer; Hash = Hash256.ComputeHash(NewContent); // New Hash if (NewContent.Length == DataLength) // Replace in situ { bw.BaseStream.Seek(DataBegin, SeekOrigin.Begin); bw.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 = ggpkContainer.LinkedFreeRecords.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) { bw.BaseStream.Seek(0, SeekOrigin.End); // Write to the end of GGPK Write(); bw.Write(NewContent); } else { FreeRecord free = bestNode.Value; bw.BaseStream.Seek(free.Offset + free.Length - Length, SeekOrigin.Begin); // Write to the FreeRecord Write(); bw.Write(NewContent); free.Length = space; if (space >= 16) // Update offset of FreeRecord { bw.BaseStream.Seek(free.Offset, SeekOrigin.Begin); bw.Write(free.Length); } else // Remove the FreeRecord { free.Remove(bestNode); } } UpdateOffset(oldOffset); // Update the offset of FileRecord in Parent.Entries/> } bw.Flush(); }