root/trunk/Updater/ICSharpCode.SharpZipLib/Zip/Compression/Streams/OutputWindow.cs @ 597

Wersja 597, 7.4 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
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
39using System;
40
41
42namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
43{
44       
45        /// <summary>
46        /// Contains the output from the Inflation process.
47        /// We need to have a window so that we can refer backwards into the output stream
48        /// to repeat stuff.<br/>
49        /// Author of the original java version : John Leuner
50        /// </summary>
51        public class OutputWindow
52        {
53                #region Constants
54                const int WindowSize = 1 << 15;
55                const int WindowMask = WindowSize - 1;
56                #endregion
57               
58                #region Instance Fields
59                byte[] window = new byte[WindowSize]; //The window is 2^15 bytes
60                int windowEnd;
61                int windowFilled;
62                #endregion
63               
64                /// <summary>
65                /// Write a byte to this output window
66                /// </summary>
67                /// <param name="value">value to write</param>
68                /// <exception cref="InvalidOperationException">
69                /// if window is full
70                /// </exception>
71                public void Write(int value)
72                {
73                        if (windowFilled++ == WindowSize) {
74                                throw new InvalidOperationException("Window full");
75                        }
76                        window[windowEnd++] = (byte) value;
77                        windowEnd &= WindowMask;
78                }
79               
80               
81                private void SlowRepeat(int repStart, int length, int distance)
82                {
83                        while (length-- > 0) {
84                                window[windowEnd++] = window[repStart++];
85                                windowEnd &= WindowMask;
86                                repStart &= WindowMask;
87                        }
88                }
89               
90                /// <summary>
91                /// Append a byte pattern already in the window itself
92                /// </summary>
93                /// <param name="length">length of pattern to copy</param>
94                /// <param name="distance">distance from end of window pattern occurs</param>
95                /// <exception cref="InvalidOperationException">
96                /// If the repeated data overflows the window
97                /// </exception>
98                public void Repeat(int length, int distance)
99                {
100                        if ((windowFilled += length) > WindowSize) {
101                                throw new InvalidOperationException("Window full");
102                        }
103                       
104                        int repStart = (windowEnd - distance) & WindowMask;
105                        int border = WindowSize - length;
106                        if ( (repStart <= border) && (windowEnd < border) ) {
107                                if (length <= distance) {
108                                        System.Array.Copy(window, repStart, window, windowEnd, length);
109                                        windowEnd += length;
110                                } else {
111                                        // We have to copy manually, since the repeat pattern overlaps.
112                                        while (length-- > 0) {
113                                                window[windowEnd++] = window[repStart++];
114                                        }
115                                }
116                        } else {
117                                SlowRepeat(repStart, length, distance);
118                        }
119                }
120               
121                /// <summary>
122                /// Copy from input manipulator to internal window
123                /// </summary>
124                /// <param name="input">source of data</param>
125                /// <param name="length">length of data to copy</param>
126                /// <returns>the number of bytes copied</returns>
127                public int CopyStored(StreamManipulator input, int length)
128                {
129                        length = Math.Min(Math.Min(length, WindowSize - windowFilled), input.AvailableBytes);
130                        int copied;
131                       
132                        int tailLen = WindowSize - windowEnd;
133                        if (length > tailLen) {
134                                copied = input.CopyBytes(window, windowEnd, tailLen);
135                                if (copied == tailLen) {
136                                        copied += input.CopyBytes(window, 0, length - tailLen);
137                                }
138                        } else {
139                                copied = input.CopyBytes(window, windowEnd, length);
140                        }
141                       
142                        windowEnd = (windowEnd + copied) & WindowMask;
143                        windowFilled += copied;
144                        return copied;
145                }
146               
147                /// <summary>
148                /// Copy dictionary to window
149                /// </summary>
150                /// <param name="dictionary">source dictionary</param>
151                /// <param name="offset">offset of start in source dictionary</param>
152                /// <param name="length">length of dictionary</param>
153                /// <exception cref="InvalidOperationException">
154                /// If window isnt empty
155                /// </exception>
156                public void CopyDict(byte[] dictionary, int offset, int length)
157                {
158                        if ( dictionary == null ) {
159                                throw new ArgumentNullException("dictionary");
160                        }
161
162                        if (windowFilled > 0) {
163                                throw new InvalidOperationException();
164                        }
165                       
166                        if (length > WindowSize) {
167                                offset += length - WindowSize;
168                                length = WindowSize;
169                        }
170                        System.Array.Copy(dictionary, offset, window, 0, length);
171                        windowEnd = length & WindowMask;
172                }
173
174                /// <summary>
175                /// Get remaining unfilled space in window
176                /// </summary>
177                /// <returns>Number of bytes left in window</returns>
178                public int GetFreeSpace()
179                {
180                        return WindowSize - windowFilled;
181                }
182               
183                /// <summary>
184                /// Get bytes available for output in window
185                /// </summary>
186                /// <returns>Number of bytes filled</returns>
187                public int GetAvailable()
188                {
189                        return windowFilled;
190                }
191
192                /// <summary>
193                /// Copy contents of window to output
194                /// </summary>
195                /// <param name="output">buffer to copy to</param>
196                /// <param name="offset">offset to start at</param>
197                /// <param name="len">number of bytes to count</param>
198                /// <returns>The number of bytes copied</returns>
199                /// <exception cref="InvalidOperationException">
200                /// If a window underflow occurs
201                /// </exception>
202                public int CopyOutput(byte[] output, int offset, int len)
203                {
204                        int copyEnd = windowEnd;
205                        if (len > windowFilled) {
206                                len = windowFilled;
207                        } else {
208                                copyEnd = (windowEnd - windowFilled + len) & WindowMask;
209                        }
210                       
211                        int copied = len;
212                        int tailLen = len - copyEnd;
213                       
214                        if (tailLen > 0) {
215                                System.Array.Copy(window, WindowSize - tailLen, output, offset, tailLen);
216                                offset += tailLen;
217                                len = copyEnd;
218                        }
219                        System.Array.Copy(window, copyEnd - len, output, offset, len);
220                        windowFilled -= copied;
221                        if (windowFilled < 0) {
222                                throw new InvalidOperationException();
223                        }
224                        return copied;
225                }
226
227                /// <summary>
228                /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0
229                /// </summary>
230                public void Reset()
231                {
232                        windowFilled = windowEnd = 0;
233                }
234        }
235}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.