Statistics
| Branch: | Revision:

root / trunk / hammock / src / net35 / ICSharpCode.SharpZipLib.Silverlight / Zip / Compression / Streams / OutputWindow.cs @ 0eea575a

History | View | Annotate | Download (8.8 kB)

1
// OutputWindow.cs
2
//
3
// Copyright (C) 2001 Mike Krueger
4
//
5
// This file was translated from java, it was part of the GNU Classpath
6
// Copyright (C) 2001 Free Software Foundation, Inc.
7
//
8
// This program is free software; you can redistribute it and/or
9
// modify it under the terms of the GNU General Public License
10
// as published by the Free Software Foundation; either version 2
11
// of the License, or (at your option) any later version.
12
//
13
// This program is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
// GNU General Public License for more details.
17
//
18
// You should have received a copy of the GNU General Public License
19
// along with this program; if not, write to the Free Software
20
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
//
22
// Linking this library statically or dynamically with other modules is
23
// making a combined work based on this library.  Thus, the terms and
24
// conditions of the GNU General Public License cover the whole
25
// combination.
26
// 
27
// As a special exception, the copyright holders of this library give you
28
// permission to link this library with independent modules to produce an
29
// executable, regardless of the license terms of these independent
30
// modules, and to copy and distribute the resulting executable under
31
// terms of your choice, provided that you also meet, for each linked
32
// independent module, the terms and conditions of the license of that
33
// module.  An independent module is a module which is not derived from
34
// or based on this library.  If you modify this library, you may extend
35
// this exception to your version of the library, but you are not
36
// obligated to do so.  If you do not wish to do so, delete this
37
// exception statement from your version.
38

    
39
using System;
40

    
41
namespace ICSharpCode.SharpZipLib.Silverlight.Zip.Compression.Streams
42
{
43
    /// <summary>
44
    /// Contains the output from the Inflation process.
45
    /// We need to have a window so that we can refer backwards into the output stream
46
    /// to repeat stuff.<br/>
47
    /// Author of the original java version : John Leuner
48
    /// </summary>
49
    public class OutputWindow
50
    {
51
        #region Constants
52

    
53
        private const int WindowMask = WindowSize - 1;
54
        private const int WindowSize = 1 << 15;
55

    
56
        #endregion
57

    
58
        #region Instance Fields
59

    
60
        private readonly byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
61
        private int windowEnd;
62
        private int windowFilled;
63

    
64
        #endregion
65

    
66
        /// <summary>
67
        /// Write a byte to this output window
68
        /// </summary>
69
        /// <param name="value">value to write</param>
70
        /// <exception cref="InvalidOperationException">
71
        /// if window is full
72
        /// </exception>
73
        public void Write(int value)
74
        {
75
            if (windowFilled++ == WindowSize)
76
            {
77
                throw new InvalidOperationException("Window full");
78
            }
79
            window[windowEnd++] = (byte) value;
80
            windowEnd &= WindowMask;
81
        }
82

    
83
        private void SlowRepeat(int repStart, int length)
84
        {
85
            while (length-- > 0)
86
            {
87
                window[windowEnd++] = window[repStart++];
88
                windowEnd &= WindowMask;
89
                repStart &= WindowMask;
90
            }
91
        }
92

    
93
        /// <summary>
94
        /// Append a byte pattern already in the window itself
95
        /// </summary>
96
        /// <param name="length">length of pattern to copy</param>
97
        /// <param name="distance">distance from end of window pattern occurs</param>
98
        /// <exception cref="InvalidOperationException">
99
        /// If the repeated data overflows the window
100
        /// </exception>
101
        public void Repeat(int length, int distance)
102
        {
103
            if ((windowFilled += length) > WindowSize)
104
            {
105
                throw new InvalidOperationException("Window full");
106
            }
107

    
108
            var repStart = (windowEnd - distance) & WindowMask;
109
            var border = WindowSize - length;
110
            if ((repStart <= border) && (windowEnd < border))
111
            {
112
                if (length <= distance)
113
                {
114
                    Array.Copy(window, repStart, window, windowEnd, length);
115
                    windowEnd += length;
116
                }
117
                else
118
                {
119
                    // We have to copy manually, since the repeat pattern overlaps.
120
                    while (length-- > 0)
121
                    {
122
                        window[windowEnd++] = window[repStart++];
123
                    }
124
                }
125
            }
126
            else
127
            {
128
                SlowRepeat(repStart, length);
129
            }
130
        }
131

    
132
        /// <summary>
133
        /// Copy from input manipulator to internal window
134
        /// </summary>
135
        /// <param name="input">source of data</param>
136
        /// <param name="length">length of data to copy</param>
137
        /// <returns>the number of bytes copied</returns>
138
        public int CopyStored(StreamManipulator input, int length)
139
        {
140
            length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
141
            int copied;
142

    
143
            var tailLen = WindowSize - windowEnd;
144
            if (length > tailLen)
145
            {
146
                copied = input.CopyBytes(window, windowEnd, tailLen);
147
                if (copied == tailLen)
148
                {
149
                    copied += input.CopyBytes(window, 0, length - tailLen);
150
                }
151
            }
152
            else
153
            {
154
                copied = input.CopyBytes(window, windowEnd, length);
155
            }
156

    
157
            windowEnd = (windowEnd + copied) & WindowMask;
158
            windowFilled += copied;
159
            return copied;
160
        }
161

    
162
        /// <summary>
163
        /// Copy dictionary to window
164
        /// </summary>
165
        /// <param name="dictionary">source dictionary</param>
166
        /// <param name="offset">offset of start in source dictionary</param>
167
        /// <param name="length">length of dictionary</param>
168
        /// <exception cref="InvalidOperationException">
169
        /// If window isnt empty
170
        /// </exception>
171
        public void CopyDict(byte[] dictionary, int offset, int length)
172
        {
173
            if (dictionary == null)
174
            {
175
                throw new ArgumentNullException("dictionary");
176
            }
177

    
178
            if (windowFilled > 0)
179
            {
180
                throw new InvalidOperationException();
181
            }
182

    
183
            if (length > WindowSize)
184
            {
185
                offset += length - WindowSize;
186
                length = WindowSize;
187
            }
188
            Array.Copy(dictionary, offset, window, 0, length);
189
            windowEnd = length & WindowMask;
190
        }
191

    
192
        /// <summary>
193
        /// Get remaining unfilled space in window
194
        /// </summary>
195
        /// <returns>Number of bytes left in window</returns>
196
        public int GetFreeSpace()
197
        {
198
            return WindowSize - windowFilled;
199
        }
200

    
201
        /// <summary>
202
        /// Get bytes available for output in window
203
        /// </summary>
204
        /// <returns>Number of bytes filled</returns>
205
        public int GetAvailable()
206
        {
207
            return windowFilled;
208
        }
209

    
210
        /// <summary>
211
        /// Copy contents of window to output
212
        /// </summary>
213
        /// <param name="output">buffer to copy to</param>
214
        /// <param name="offset">offset to start at</param>
215
        /// <param name="len">number of bytes to count</param>
216
        /// <returns>The number of bytes copied</returns>
217
        /// <exception cref="InvalidOperationException">
218
        /// If a window underflow occurs
219
        /// </exception>
220
        public int CopyOutput(byte[] output, int offset, int len)
221
        {
222
            var copyEnd = windowEnd;
223
            if (len > windowFilled)
224
            {
225
                len = windowFilled;
226
            }
227
            else
228
            {
229
                copyEnd = (windowEnd - windowFilled + len) & WindowMask;
230
            }
231

    
232
            var copied = len;
233
            var tailLen = len - copyEnd;
234

    
235
            if (tailLen > 0)
236
            {
237
                Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
238
                offset += tailLen;
239
                len = copyEnd;
240
            }
241
            Array.Copy(window, copyEnd - len, output, offset, len);
242
            windowFilled -= copied;
243
            if (windowFilled < 0)
244
            {
245
                throw new InvalidOperationException();
246
            }
247
            return copied;
248
        }
249

    
250
        /// <summary>
251
        /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
252
        /// </summary>
253
        public void Reset()
254
        {
255
            windowFilled = windowEnd = 0;
256
        }
257
    }
258
}