/// <summary> /// Creates a ONE archive from a set of files. /// </summary> /// <param name="files">The files to create an archive from.</param> /// <param name="version">The version of the archive. Heroes' default is 3.5.0.0. Consider using 3.3.0.0 to support all available prototypes.</param> /// <param name="bufferSize">Size of the search buffer used in compression between 0-8191.</param> public static byte[] FromFiles(IList <ManagedOneFile> files, RwVersion version, int bufferSize = 255) { // Compress all files. files = files.Select(x => new ManagedOneFile(x.Name, x.GetCompressedData(bufferSize), true)).ToArray(); // Calculate sizes. var numberOfFiles = files.Count + 2; // Two dummy entries. var sizeOfHeaders = sizeof(OneArchiveHeader) + sizeof(OneNameSectionHeader); var sizeOfNameSection = sizeof(OneFileName) * numberOfFiles; var sizeOfFileSection = files.Sum(x => x.GetCompressedData().Length + sizeof(OneFileEntry)); var totalSize = sizeOfHeaders + sizeOfNameSection + sizeOfFileSection; // Make file. using var memStream = new ExtendedMemoryStream(totalSize); memStream.Append(new OneArchiveHeader(totalSize - sizeof(OneArchiveHeader), version)); memStream.Append(new OneNameSectionHeader(sizeOfNameSection, version)); memStream.Append(new OneFileName("")); // Dummy entries memStream.Append(new OneFileName("")); foreach (var file in files) { memStream.Append(new OneFileName(file.Name)); } int nameSectionIndex = 2; foreach (var file in files) { memStream.Append(new OneFileEntry(nameSectionIndex++, file.GetCompressedData().Length, file.RwVersion)); memStream.Append(file.GetCompressedData()); } return(memStream.ToArray()); }
/// <summary> /// Builds a virtual AFS based upon a supplied base AFS file. /// </summary> public VirtualAfs Build(string afsFilePath, int alignment = 2048) { // Get entries from original AFS file. var entries = GetEntriesFromFile(afsFilePath); var files = new Dictionary <int, VirtualFile>(entries.Length); // Get Original File List and Copy to New Header. var maxCustomFileId = _customFiles.Count > 0 ? _customFiles.Max(x => x.Key) + 1 : 0; var numFiles = Math.Max(maxCustomFileId, entries.Length); var newEntries = new AfsFileEntry[numFiles]; var headerLength = Utilities.RoundUp(sizeof(AfsHeader) + (sizeof(AfsFileEntry) * entries.Length), alignment); // Create new Virtual AFS Header for (int x = 0; x < entries.Length; x++) { var offset = x > 0 ? Utilities.RoundUp(newEntries[x - 1].Offset + newEntries[x - 1].Length, alignment) : entries[0].Offset; int length = 0; if (_customFiles.ContainsKey(x)) { length = _customFiles[x].Length; files[offset] = _customFiles[x]; } else { length = entries[x].Length; files[offset] = new VirtualFile(entries[x], afsFilePath); } newEntries[x] = new AfsFileEntry(offset, length); } var lastEntry = newEntries.Last(); var fileSize = Utilities.RoundUp(lastEntry.Offset + lastEntry.Length, alignment); // Make Header using var memStream = new ExtendedMemoryStream(headerLength); memStream.Append(AfsHeader.FromNumberOfFiles(newEntries.Length)); memStream.Append(newEntries); memStream.Append(new AfsFileEntry(0, 0)); memStream.AddPadding(alignment); return(new VirtualAfs(memStream.ToArray(), files, alignment, fileSize)); }