File: AbstractWritableArchive.cs

package info (click to toggle)
mono-reference-assemblies 3.12.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 604,240 kB
  • ctags: 625,505
  • sloc: cs: 3,967,741; xml: 2,793,081; ansic: 418,042; java: 60,435; sh: 14,833; makefile: 11,576; sql: 7,956; perl: 1,467; cpp: 1,446; yacc: 1,203; python: 598; asm: 422; sed: 16; php: 1
file content (139 lines) | stat: -rw-r--r-- 4,709 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;

namespace SharpCompress.Archive
{
    internal abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
        where TEntry : IArchiveEntry
        where TVolume : IVolume
    {
        private readonly List<TEntry> newEntries = new List<TEntry>();
        private readonly List<TEntry> removedEntries = new List<TEntry>();

        private readonly List<TEntry> modifiedEntries = new List<TEntry>();
        private bool hasModifications;

        internal AbstractWritableArchive(ArchiveType type)
            : base(type)
        {
        }

        internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
            : base(type, stream.AsEnumerable(), options, null)
        {
        }

#if !PORTABLE && !NETFX_CORE
        internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
            : base(type, fileInfo, options, null)
        {
        }
#endif

        public override ICollection<TEntry> Entries
        {
            get
            {
                if (hasModifications)
                {
                    return modifiedEntries;
                }
                return base.Entries;
            }
        }

        private void RebuildModifiedCollection()
        {
            hasModifications = true;
            newEntries.RemoveAll(v => removedEntries.Contains(v));
            modifiedEntries.Clear();
            modifiedEntries.AddRange(OldEntries.Concat(newEntries));
        }

        private IEnumerable<TEntry> OldEntries
        {
            get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
        }

        public void RemoveEntry(TEntry entry)
        {
            if (!removedEntries.Contains(entry))
            {
                removedEntries.Add(entry);
                RebuildModifiedCollection();
            }
        }

        public TEntry AddEntry(string key, Stream source,
                             long size = 0, DateTime? modified = null)
        {
            return AddEntry(key, source, false, size, modified);
        }

        public TEntry AddEntry(string key, Stream source, bool closeStream,
                             long size = 0, DateTime? modified = null)
        {
            if (key.StartsWith("/")
                || key.StartsWith("\\"))
            {
                key = key.Substring(1);
            }
            if (DoesKeyMatchExisting(key))
            {
                throw new ArchiveException("Cannot add entry with duplicate key: " + key);
            }
            var entry = CreateEntry(key, source, size, modified, closeStream);
            newEntries.Add(entry);
            RebuildModifiedCollection();
            return entry;
        }

        private bool DoesKeyMatchExisting(string key)
        {
            foreach (var path in Entries.Select(x => x.Key))
            {
                var p = path.Replace('/','\\');
                if (p.StartsWith("\\"))
                {
                    p = p.Substring(1);
                }
                return string.Equals(p, key, StringComparison.OrdinalIgnoreCase);
            }
            return false;
        }

        public void SaveTo(Stream stream, CompressionInfo compressionType)
        {
            //reset streams of new entries
            newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
            SaveTo(stream, compressionType, OldEntries, newEntries);
        }

        protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
            bool closeStream)
        {
            if (!source.CanRead || !source.CanSeek)
            {
                throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
            }
            return CreateEntryInternal(key, source, size, modified, closeStream);
        }

        protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
                                              bool closeStream);

        protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
                                       IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);

        public override void Dispose()
        {
            base.Dispose();
            newEntries.Cast<Entry>().ForEach(x => x.Close());
            removedEntries.Cast<Entry>().ForEach(x => x.Close());
            modifiedEntries.Cast<Entry>().ForEach(x => x.Close());
        }
    }
}