* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / ICSharpCode.SharpZipLib / ICSharpCode.SharpZipLib / Zip / Compression / Streams / OutputWindow.cs
1 // OutputWindow.cs\r
2 //\r
3 // Copyright (C) 2001 Mike Krueger\r
4 //\r
5 // This file was translated from java, it was part of the GNU Classpath\r
6 // Copyright (C) 2001 Free Software Foundation, Inc.\r
7 //\r
8 // This program is free software; you can redistribute it and/or\r
9 // modify it under the terms of the GNU General Public License\r
10 // as published by the Free Software Foundation; either version 2\r
11 // of the License, or (at your option) any later version.\r
12 //\r
13 // This program is distributed in the hope that it will be useful,\r
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16 // GNU General Public License for more details.\r
17 //\r
18 // You should have received a copy of the GNU General Public License\r
19 // along with this program; if not, write to the Free Software\r
20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
21 //\r
22 // Linking this library statically or dynamically with other modules is\r
23 // making a combined work based on this library.  Thus, the terms and\r
24 // conditions of the GNU General Public License cover the whole\r
25 // combination.\r
26 // \r
27 // As a special exception, the copyright holders of this library give you\r
28 // permission to link this library with independent modules to produce an\r
29 // executable, regardless of the license terms of these independent\r
30 // modules, and to copy and distribute the resulting executable under\r
31 // terms of your choice, provided that you also meet, for each linked\r
32 // independent module, the terms and conditions of the license of that\r
33 // module.  An independent module is a module which is not derived from\r
34 // or based on this library.  If you modify this library, you may extend\r
35 // this exception to your version of the library, but you are not\r
36 // obligated to do so.  If you do not wish to do so, delete this\r
37 // exception statement from your version.\r
38 \r
39 using System;\r
40 \r
41 namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams \r
42 {\r
43         \r
44         /// <summary>\r
45         /// Contains the output from the Inflation process.\r
46         /// We need to have a window so that we can refer backwards into the output stream\r
47         /// to repeat stuff.<br/>\r
48         /// Author of the original java version : John Leuner\r
49         /// </summary>\r
50         public class OutputWindow\r
51         {\r
52                 private static int WINDOW_SIZE = 1 << 15;\r
53                 private static int WINDOW_MASK = WINDOW_SIZE - 1;\r
54                 \r
55                 private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes\r
56                 private int windowEnd  = 0;\r
57                 private int windowFilled = 0;\r
58                 \r
59                 /// <summary>\r
60                 /// Write a byte to this output window\r
61                 /// </summary>\r
62                 /// <param name="abyte">value to write</param>\r
63                 /// <exception cref="InvalidOperationException">\r
64                 /// if window is full\r
65                 /// </exception>\r
66                 public void Write(int abyte)\r
67                 {\r
68                         if (windowFilled++ == WINDOW_SIZE) {\r
69                                 throw new InvalidOperationException("Window full");\r
70                         }\r
71                         window[windowEnd++] = (byte) abyte;\r
72                         windowEnd &= WINDOW_MASK;\r
73                 }\r
74                 \r
75                 \r
76                 private void SlowRepeat(int repStart, int len, int dist)\r
77                 {\r
78                         while (len-- > 0) {\r
79                                 window[windowEnd++] = window[repStart++];\r
80                                 windowEnd &= WINDOW_MASK;\r
81                                 repStart &= WINDOW_MASK;\r
82                         }\r
83                 }\r
84                 \r
85                 /// <summary>\r
86                 /// Append a byte pattern already in the window itself\r
87                 /// </summary>\r
88                 /// <param name="len">length of pattern to copy</param>\r
89                 /// <param name="dist">distance from end of window pattern occurs</param>\r
90                 /// <exception cref="InvalidOperationException">\r
91                 /// If the repeated data overflows the window\r
92                 /// </exception>\r
93                 public void Repeat(int len, int dist)\r
94                 {\r
95                         if ((windowFilled += len) > WINDOW_SIZE) {\r
96                                 throw new InvalidOperationException("Window full");\r
97                         }\r
98                         \r
99                         int rep_start = (windowEnd - dist) & WINDOW_MASK;\r
100                         int border = WINDOW_SIZE - len;\r
101                         if (rep_start <= border && windowEnd < border) {\r
102                                 if (len <= dist) {\r
103                                         System.Array.Copy(window, rep_start, window, windowEnd, len);\r
104                                         windowEnd += len;\r
105                                 } else {\r
106                                         /* We have to copy manually, since the repeat pattern overlaps. */\r
107                                         while (len-- > 0) {\r
108                                                 window[windowEnd++] = window[rep_start++];\r
109                                         }\r
110                                 }\r
111                         } else {\r
112                                 SlowRepeat(rep_start, len, dist);\r
113                         }\r
114                 }\r
115                 \r
116                 /// <summary>\r
117                 /// Copy from input manipulator to internal window\r
118                 /// </summary>\r
119                 /// <param name="input">source of data</param>\r
120                 /// <param name="len">length of data to copy</param>\r
121                 /// <returns>the number of bytes copied</returns>\r
122                 public int CopyStored(StreamManipulator input, int len)\r
123                 {\r
124                         len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);\r
125                         int copied;\r
126                         \r
127                         int tailLen = WINDOW_SIZE - windowEnd;\r
128                         if (len > tailLen) {\r
129                                 copied = input.CopyBytes(window, windowEnd, tailLen);\r
130                                 if (copied == tailLen) {\r
131                                         copied += input.CopyBytes(window, 0, len - tailLen);\r
132                                 }\r
133                         } else {\r
134                                 copied = input.CopyBytes(window, windowEnd, len);\r
135                         }\r
136                         \r
137                         windowEnd = (windowEnd + copied) & WINDOW_MASK;\r
138                         windowFilled += copied;\r
139                         return copied;\r
140                 }\r
141                 \r
142                 /// <summary>\r
143                 /// Copy dictionary to window\r
144                 /// </summary>\r
145                 /// <param name="dict">source dictionary</param>\r
146                 /// <param name="offset">offset of start in source dictionary</param>\r
147                 /// <param name="len">length of dictionary</param>\r
148                 /// <exception cref="InvalidOperationException">\r
149                 /// If window isnt empty\r
150                 /// </exception>\r
151                 public void CopyDict(byte[] dict, int offset, int len)\r
152                 {\r
153                         if (windowFilled > 0) {\r
154                                 throw new InvalidOperationException();\r
155                         }\r
156                         \r
157                         if (len > WINDOW_SIZE) {\r
158                                 offset += len - WINDOW_SIZE;\r
159                                 len = WINDOW_SIZE;\r
160                         }\r
161                         System.Array.Copy(dict, offset, window, 0, len);\r
162                         windowEnd = len & WINDOW_MASK;\r
163                 }\r
164 \r
165                 /// <summary>\r
166                 /// Get remaining unfilled space in window\r
167                 /// </summary>\r
168                 /// <returns>Number of bytes left in window</returns>\r
169                 public int GetFreeSpace()\r
170                 {\r
171                         return WINDOW_SIZE - windowFilled;\r
172                 }\r
173                 \r
174                 /// <summary>\r
175                 /// Get bytes available for output in window\r
176                 /// </summary>\r
177                 /// <returns>Number of bytes filled</returns>\r
178                 public int GetAvailable()\r
179                 {\r
180                         return windowFilled;\r
181                 }\r
182 \r
183                 /// <summary>\r
184                 /// Copy contents of window to output\r
185                 /// </summary>\r
186                 /// <param name="output">buffer to copy to</param>\r
187                 /// <param name="offset">offset to start at</param>\r
188                 /// <param name="len">number of bytes to count</param>\r
189                 /// <returns>The number of bytes copied</returns>\r
190                 /// <exception cref="InvalidOperationException">\r
191                 /// If a window underflow occurs\r
192                 /// </exception>\r
193                 public int CopyOutput(byte[] output, int offset, int len)\r
194                 {\r
195                         int copy_end = windowEnd;\r
196                         if (len > windowFilled) {\r
197                                 len = windowFilled;\r
198                         } else {\r
199                                 copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;\r
200                         }\r
201                         \r
202                         int copied = len;\r
203                         int tailLen = len - copy_end;\r
204                         \r
205                         if (tailLen > 0) {\r
206                                 System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);\r
207                                 offset += tailLen;\r
208                                 len = copy_end;\r
209                         }\r
210                         System.Array.Copy(window, copy_end - len, output, offset, len);\r
211                         windowFilled -= copied;\r
212                         if (windowFilled < 0) {\r
213                                 throw new InvalidOperationException();\r
214                         }\r
215                         return copied;\r
216                 }\r
217 \r
218                 /// <summary>\r
219                 /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0\r
220                 /// </summary>\r
221                 public void Reset()\r
222                 {\r
223                         windowFilled = windowEnd = 0;\r
224                 }\r
225         }\r
226 }\r