public void Save(Stream output, IList <IArchiveFileInfo> files) { var headerTableSize = _header.CalculateSize(); long tableOffset = headerTableSize; // Write files and toc table if (_tocTable != null) { WriteTocTable(output, files, tableOffset); tableOffset = output.Length; } if (_itocTable != null) { WriteItocTable(output, files, tableOffset); tableOffset = output.Length; } if (_etocTable != null) { WriteEtocTable(output, tableOffset); tableOffset = output.Length; } // Write header _header.Write(output, 0); }
private void WriteTable(Stream output, CpkTable table, long tableOffset, string offsetName, string sizeName) { var tocTableSize = table.CalculateSize(); var tocOffset = CpkSupport.Align(tableOffset, _align); table.Write(output, tocOffset, _align); WriteAlignment(output, 0x10); _header.Rows[0].Set(offsetName, tocOffset); _header.Rows[0].Set(sizeName, (long)tocTableSize); }
private void WriteEtocTable(Stream output, long tableOffset) { var tocTableSize = _etocTable.CalculateSize(); var tocOffset = CpkSupport.Align(tableOffset, _align); _etocTable.Write(output, tocOffset); WriteAlignment(output, 0x10); _header.Rows[0].Set("EtocOffset", tocOffset); _header.Rows[0].Set("EtocSize", (long)tocTableSize); }
private void WriteTocTable(Stream output, IList <IArchiveFileInfo> files, long tableOffset, long fileOffset) { // Update file information foreach (var file in files.Cast <CpkArchiveFileInfo>()) { file.Row.Set("DirName", file.FilePath.ToRelative().GetDirectory().FullName); file.Row.Set("FileName", file.FilePath.GetName()); file.Row.Set("ExtractSize", (int)file.FileSize); } var tocTableSize = _tocTable.CalculateSize(); var tocOffset = CpkSupport.Align(tableOffset, _align); fileOffset = CpkSupport.Align(fileOffset, _align); var filePosition = fileOffset; // Write files and update remaining file information foreach (var file in files.Cast <CpkArchiveFileInfo>().OrderBy(x => x.Row.Get <int>("ID"))) { // Update offset file.Row.Set("FileOffset", filePosition - tocOffset); // Write file output.Position = filePosition; var writtenSize = file.SaveFileData(output); while (output.Position % _align > 0) { output.WriteByte(0); } filePosition = output.Position; // Update compressed size // HINT: This code allows for the scenario that the table size was calculated to have a const value for FileSize, instead of a row value, // since it works on previous data. Setting FileSize before calculating the table size however, would require // caching all compressed files either in memory or in a temporary file. // Since it is very unlikely that every compressed file has either the same size or every file is not compressed, // we only update the FileSize here. This gains memory efficiency over a very unlikely case of wrong table size. file.Row.Set("FileSize", (int)writtenSize); } // Write table _tocTable.Write(output, tocOffset, _align); // Update header _header.Rows[0].Set("TocOffset", (long)tocOffset); _header.Rows[0].Set("ContentOffset", fileOffset); _header.Rows[0].Set("TocSize", (long)tocTableSize); _header.Rows[0].Set("ContentSize", filePosition - fileOffset); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { var headerTableSize = _header.CalculateSize(); long tableOffset = headerTableSize; var fileOffset = tableOffset + CpkSupport.Align(_tocTable?.CalculateSize() ?? 0, _align) + CpkSupport.Align(_etocTable?.CalculateSize() ?? 0, _align) + CpkSupport.Align(_itocTable?.CalculateSize() ?? 0, _align) + CpkSupport.Align(_gtocTable?.CalculateSize() ?? 0, _align); // Write files and toc table if (_tocTable != null) { WriteTocTable(output, files, tableOffset, fileOffset); tableOffset = CpkSupport.Align(tableOffset, _align) + _tocTable.CalculateSize(); } if (_itocTable != null) { WriteItocTable(output, files, tableOffset, fileOffset); tableOffset = CpkSupport.Align(tableOffset, _align) + _itocTable.CalculateSize(); } if (_etocTable != null) { WriteEtocTable(output, tableOffset); tableOffset = CpkSupport.Align(tableOffset, _align) + _etocTable.CalculateSize(); } if (_gtocTable != null) { WriteGtocTable(output, tableOffset); tableOffset = CpkSupport.Align(tableOffset, _align) + _gtocTable.CalculateSize(); } // Write header _header.Write(output, 0, _align); }
private void WriteItocFileTable(Stream output, IList <IArchiveFileInfo> files, long tableOffset, long fileOffset) { // Update file information foreach (var file in files.Cast <CpkArchiveFileInfo>()) { file.Row.Set("ExtractSize", (int)file.FileSize); } var tocTableSize = _itocTable.CalculateSize(); var tocOffset = CpkSupport.Align(tableOffset, _align); var filePosition = fileOffset; // Write files and update remaining file information foreach (var file in files.Cast <CpkArchiveFileInfo>().OrderBy(x => int.Parse(x.FilePath.GetNameWithoutExtension()))) { // Write file output.Position = filePosition; var writtenSize = file.SaveFileData(output); while (output.Position % _align > 0) { output.WriteByte(0); } filePosition = output.Position; // Update compressed size // HINT: This code allows for the scenario that the table size was calculated to have a const value for FileSize, // since it works on previous data. Setting FileSize before calculating the table size however, would require // caching all compressed files either in memory or in a temporary file. // Since it is very unlikely that every compressed file has either the same size or every file is not compressed, // we only update the FileSize here. This gains memory efficiency over a very unlikely case of wrong table size. file.Row.Set("FileSize", (int)writtenSize); // Rearrange row into correct data table if (writtenSize <= 0xFFFF && _dataHTable.Rows.Contains(file.Row)) { _dataHTable.Rows.Remove(file.Row); _dataLTable.Rows.Add(file.Row); } else if (writtenSize >= 0x10000 && _dataLTable.Rows.Contains(file.Row)) { _dataLTable.Rows.Remove(file.Row); _dataHTable.Rows.Add(file.Row); } } // Store written data tables var dataLStream = new MemoryStream(); _dataLTable.Write(dataLStream, 0, _align, false); WriteAlignment(dataLStream, 0x10); var dataHStream = new MemoryStream(); _dataHTable.Write(dataHStream, 0, _align, false); WriteAlignment(dataHStream, 0x10); // Update and write table _itocTable.Rows[0].Set("DataL", dataLStream.ToArray()); _itocTable.Rows[0].Set("DataH", dataHStream.ToArray()); _itocTable.Rows[0].Set("FilesL", _dataLTable.Rows.Count); _itocTable.Rows[0].Set("FilesH", _dataHTable.Rows.Count); _itocTable.Write(output, tocOffset, _align); // Update header _header.Rows[0].Set("ItocOffset", (long)tocOffset); _header.Rows[0].Set("ContentOffset", fileOffset); _header.Rows[0].Set("ItocSize", (long)tocTableSize); _header.Rows[0].Set("ContentSize", filePosition - fileOffset); }