2 using System.Collections.Generic;
5 using SharpCompress.Common;
7 namespace SharpCompress.Archive
9 internal abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
10 where TEntry : IArchiveEntry
11 where TVolume : IVolume
13 private readonly List<TEntry> newEntries = new List<TEntry>();
14 private readonly List<TEntry> removedEntries = new List<TEntry>();
16 private readonly List<TEntry> modifiedEntries = new List<TEntry>();
17 private bool hasModifications;
19 internal AbstractWritableArchive(ArchiveType type)
24 internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
25 : base(type, stream.AsEnumerable(), options, null)
29 #if !PORTABLE && !NETFX_CORE
30 internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
31 : base(type, fileInfo, options, null)
36 public override ICollection<TEntry> Entries
42 return modifiedEntries;
48 private void RebuildModifiedCollection()
50 hasModifications = true;
51 newEntries.RemoveAll(v => removedEntries.Contains(v));
52 modifiedEntries.Clear();
53 modifiedEntries.AddRange(OldEntries.Concat(newEntries));
56 private IEnumerable<TEntry> OldEntries
58 get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
61 public void RemoveEntry(TEntry entry)
63 if (!removedEntries.Contains(entry))
65 removedEntries.Add(entry);
66 RebuildModifiedCollection();
70 public TEntry AddEntry(string key, Stream source,
71 long size = 0, DateTime? modified = null)
73 return AddEntry(key, source, false, size, modified);
76 public TEntry AddEntry(string key, Stream source, bool closeStream,
77 long size = 0, DateTime? modified = null)
79 if (key.StartsWith("/")
80 || key.StartsWith("\\"))
82 key = key.Substring(1);
84 if (DoesKeyMatchExisting(key))
86 throw new ArchiveException("Cannot add entry with duplicate key: " + key);
88 var entry = CreateEntry(key, source, size, modified, closeStream);
89 newEntries.Add(entry);
90 RebuildModifiedCollection();
94 private bool DoesKeyMatchExisting(string key)
96 foreach (var path in Entries.Select(x => x.Key))
98 var p = path.Replace('/','\\');
99 if (p.StartsWith("\\"))
103 return string.Equals(p, key, StringComparison.OrdinalIgnoreCase);
108 public void SaveTo(Stream stream, CompressionInfo compressionType)
110 //reset streams of new entries
111 newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
112 SaveTo(stream, compressionType, OldEntries, newEntries);
115 protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
118 if (!source.CanRead || !source.CanSeek)
120 throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
122 return CreateEntryInternal(key, source, size, modified, closeStream);
125 protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
128 protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
129 IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
131 public override void Dispose()
134 newEntries.Cast<Entry>().ForEach(x => x.Close());
135 removedEntries.Cast<Entry>().ForEach(x => x.Close());
136 modifiedEntries.Cast<Entry>().ForEach(x => x.Close());