public override Stream Encode(bool _ = false) { Stream fSysStream = $"{Path}/{FileName}.repak".GetNewStream(); if (ExtractedEntries.Count == 0) { // nothing extracted, nothing changed // just copy the existing stream back ExtractedFile.Seek(0, SeekOrigin.Begin); ExtractedFile.CopyTo(fSysStream); return(fSysStream); } // unpack the entire fsys archive for easier repacking if (ExtractedEntries.Count < NumberOfEntries) { FSysExtractor.ExtractFSys(this, false); } // copy the header back, we'll update the sizes later NumberOfEntries = ExtractedEntries.Count; ExtractedFile.Seek(0, SeekOrigin.Begin); ExtractedFile.CopySubStream(fSysStream, 0, 0x60); var sizeOfDetailsPointers = (fSysDetailsHeaders.Count * 4); var startNameOffset = 0x60 + sizeOfDetailsPointers + sizeOfDetailsPointers.GetAlignBytesCount(16); fSysStream.Seek(startNameOffset, SeekOrigin.Begin); // write the name table var startDataOffset = uint.MaxValue; foreach (var detailHeader in fSysDetailsHeaders) { fSysStream.Write(detailHeader.FileName.ToByteArray()); fSysStream.WriteByte(0); if (detailHeader.StartOffset < startDataOffset) { startDataOffset = detailHeader.StartOffset; } } // align names fSysStream.AlignStream(0x10); var lastNameOffset = (int)fSysStream.Position; var startDetailsOffsewt = 0x60; // write pointers to details offset fSysStream.Seek(startDetailsOffsewt, SeekOrigin.Begin); for (int x = 0; x < fSysDetailsHeaders.Count; x++) { fSysStream.Write((lastNameOffset + (x * 0x70)).GetBytes()); } // write our data, update offsets along the way if we find mismatches for (int i = 0; i < fSysDetailsHeaders.Count; i++) { var detailHeader = fSysDetailsHeaders[i]; var entryFileName = detailHeader.FileName.ToString(); if (!entryFileName.EndsWith(detailHeader.Filetype.FileTypeName())) { entryFileName = $"{entryFileName}{detailHeader.Filetype.FileTypeName()}"; } var entry = ExtractedEntries[entryFileName]; using var encodeStream = entry.Encode(detailHeader.IsCompressed); fSysStream.Seek(detailHeader.StartOffset, SeekOrigin.Begin); encodeStream.CopyTo(fSysStream); fSysStream.Flush(); detailHeader.UncompressedSize = (uint)entry.ExtractedFile.Length; if (encodeStream.Length != detailHeader.CompressedSize) { var adjustedSize = (int)(encodeStream.Length - detailHeader.CompressedSize); detailHeader.CompressedSize = (uint)encodeStream.Length; if (adjustedSize < 0) { continue; // probably wasteful, but meh } for (int j = i + 1; j < fSysDetailsHeaders.Count; j++) { var adjDetailsHeader = fSysDetailsHeaders[j]; adjDetailsHeader.StartOffset += (uint)adjustedSize; adjDetailsHeader.StartOffset += adjDetailsHeader.StartOffset.GetAlignBytesCount(0x10); } } } fSysStream.AlignStream(0x10); fSysStream.Write(new byte[0x10]); fSysStream.Seek(-4, SeekOrigin.Current); fSysStream.Write(FSYSbytes.GetBytes()); fSysStream.Flush(); fSysStream.WriteBytesAtOffset(FSYSFileSizeOffset, ((int)fSysStream.Length).GetBytes()); // go back and re-write our file details table fSysStream.Seek(lastNameOffset, SeekOrigin.Begin); foreach (var detailHeader in fSysDetailsHeaders) { fSysStream.Write(detailHeader.Encode()); } fSysStream.Flush(); fSysStream.Seek(0, SeekOrigin.Begin); return(fSysStream); }