public NpkWriter(NpkStoredEntry entry, Stream archive, Aes aes) { m_input = File.OpenRead(entry.Name); m_archive = archive; m_entry = entry; m_aes = aes; m_buffer = null; }
public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options, EntryCallback callback) { var npk_options = GetOptions <Npk2Options> (options); if (null == npk_options.Key) { throw new InvalidEncryptionScheme(); } var enc = DefaultEncoding.WithFatalFallback(); int index_length = 0; var dir = new List <NpkStoredEntry>(); foreach (var entry in list) { var ext = Path.GetExtension(entry.Name).ToLowerInvariant(); var npk_entry = new NpkStoredEntry { Name = entry.Name, RawName = enc.GetBytes(entry.Name.Replace('\\', '/')), IsSolid = SolidFiles.Contains(ext), IsPacked = !DisableCompression.Contains(ext), }; int segment_count = 1; if (!npk_entry.IsSolid) { segment_count = (int)(((long)entry.Size + DefaultSegmentSize - 1) / DefaultSegmentSize); } index_length += 3 + npk_entry.RawName.Length + 0x28 + segment_count * 0x14; dir.Add(npk_entry); } index_length = (index_length + 0xF) & ~0xF; int callback_count = 0; using (var aes = Aes.Create()) { aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; aes.Key = npk_options.Key; aes.IV = GenerateAesIV(); output.Position = 0x20 + index_length; foreach (var entry in dir) { if (null != callback) { callback(callback_count++, entry, arcStrings.MsgAddingFile); } using (var writer = new NpkWriter(entry, output, aes)) writer.Write(DefaultSegmentSize); } output.Position = 0; var buffer = new byte[] { (byte)'N', (byte)'P', (byte)'K', (byte)'2', 1, 0, 0, 0 }; output.Write(buffer, 0, 8); output.Write(aes.IV, 0, 0x10); LittleEndian.Pack(dir.Count, buffer, 0); LittleEndian.Pack(index_length, buffer, 4); output.Write(buffer, 0, 8); using (var encryptor = aes.CreateEncryptor()) using (var proxy = new ProxyStream(output, true)) using (var index_stream = new CryptoStream(proxy, encryptor, CryptoStreamMode.Write)) using (var index = new BinaryWriter(index_stream)) { if (null != callback) { callback(callback_count++, null, arcStrings.MsgWritingIndex); } foreach (var entry in dir) { index.Write(entry.IsSolid); // 0 -> segmentation enabled, 1 -> no segmentation index.Write((short)entry.RawName.Length); index.Write(entry.RawName); index.Write(entry.UnpackedSize); index.Write(entry.CheckSum); index.Write(entry.Segments.Count); foreach (var segment in entry.Segments) { index.Write(segment.Offset); index.Write(segment.AlignedSize); index.Write(segment.Size); index.Write(segment.UnpackedSize); } } } } }