2 using System.Collections.Generic;
6 using SharpCompress.Common;
8 namespace SharpCompress.Archive
10 internal abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
11 where TEntry : IArchiveEntry
12 where TVolume : IVolume
14 private readonly List<TEntry> newEntries = new List<TEntry>();
15 private readonly List<TEntry> removedEntries = new List<TEntry>();
17 private readonly List<TEntry> modifiedEntries = new List<TEntry>();
18 private bool hasModifications;
20 internal AbstractWritableArchive(ArchiveType type)
25 internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
26 : base(type, stream.AsEnumerable(), options, null)
30 #if !PORTABLE && !NETFX_CORE
31 internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
32 : base(type, fileInfo, options, null)
37 public override ICollection<TEntry> Entries
43 return modifiedEntries;
49 private void RebuildModifiedCollection()
51 hasModifications = true;
52 newEntries.RemoveAll(v => removedEntries.Contains(v));
53 modifiedEntries.Clear();
54 modifiedEntries.AddRange(OldEntries.Concat(newEntries));
57 private IEnumerable<TEntry> OldEntries
59 get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
62 public void RemoveEntry(TEntry entry)
64 if (!removedEntries.Contains(entry))
66 removedEntries.Add(entry);
67 RebuildModifiedCollection();
71 public TEntry AddEntry(string key, Stream source,
72 long size = 0, DateTime? modified = null)
74 return AddEntry(key, source, false, size, modified);
77 public TEntry AddEntry(string key, Stream source, bool closeStream,
78 long size = 0, DateTime? modified = null)
80 if (key.StartsWith("/")
81 || key.StartsWith("\\"))
83 key = key.Substring(1);
85 if (DoesKeyMatchExisting(key))
87 throw new ArchiveException("Cannot add entry with duplicate key: " + key);
89 var entry = CreateEntry(key, source, size, modified, closeStream);
90 newEntries.Add(entry);
91 RebuildModifiedCollection();
95 private bool DoesKeyMatchExisting(string key)
97 foreach (var path in Entries.Select(x => x.Key))
99 var p = path.Replace('/','\\');
100 if (p.StartsWith("\\"))
104 return string.Equals(p, key, StringComparison.OrdinalIgnoreCase);
109 public void SaveTo(Stream stream, CompressionInfo compressionType, Encoding encoding = null)
111 //reset streams of new entries
112 newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
113 SaveTo(stream, compressionType, encoding ?? ArchiveEncoding.Default, OldEntries, newEntries);
116 protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
119 if (!source.CanRead || !source.CanSeek)
121 throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
123 return CreateEntryInternal(key, source, size, modified, closeStream);
126 protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
129 protected abstract void SaveTo(Stream stream, CompressionInfo compressionType, Encoding encoding,
130 IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
132 public override void Dispose()
135 newEntries.Cast<Entry>().ForEach(x => x.Close());
136 removedEntries.Cast<Entry>().ForEach(x => x.Close());
137 modifiedEntries.Cast<Entry>().ForEach(x => x.Close());