git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.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 PdfSharp.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   internal 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       {\r
70         throw new InvalidOperationException("Window full");\r
71       }\r
72       window[windowEnd++] = (byte)abyte;\r
73       windowEnd &= WINDOW_MASK;\r
74     }\r
75 \r
76 \r
77     private void SlowRepeat(int repStart, int len, int dist)\r
78     {\r
79       while (len-- > 0)\r
80       {\r
81         window[windowEnd++] = window[repStart++];\r
82         windowEnd &= WINDOW_MASK;\r
83         repStart &= WINDOW_MASK;\r
84       }\r
85     }\r
86 \r
87     /// <summary>\r
88     /// Append a byte pattern already in the window itself\r
89     /// </summary>\r
90     /// <param name="len">length of pattern to copy</param>\r
91     /// <param name="dist">distance from end of window pattern occurs</param>\r
92     /// <exception cref="InvalidOperationException">\r
93     /// If the repeated data overflows the window\r
94     /// </exception>\r
95     public void Repeat(int len, int dist)\r
96     {\r
97       if ((windowFilled += len) > WINDOW_SIZE)\r
98       {\r
99         throw new InvalidOperationException("Window full");\r
100       }\r
101 \r
102       int rep_start = (windowEnd - dist) & WINDOW_MASK;\r
103       int border = WINDOW_SIZE - len;\r
104       if (rep_start <= border && windowEnd < border)\r
105       {\r
106         if (len <= dist)\r
107         {\r
108           System.Array.Copy(window, rep_start, window, windowEnd, len);\r
109           windowEnd += len;\r
110         }\r
111         else\r
112         {\r
113           /* We have to copy manually, since the repeat pattern overlaps. */\r
114           while (len-- > 0)\r
115           {\r
116             window[windowEnd++] = window[rep_start++];\r
117           }\r
118         }\r
119       }\r
120       else\r
121       {\r
122         SlowRepeat(rep_start, len, dist);\r
123       }\r
124     }\r
125 \r
126     /// <summary>\r
127     /// Copy from input manipulator to internal window\r
128     /// </summary>\r
129     /// <param name="input">source of data</param>\r
130     /// <param name="len">length of data to copy</param>\r
131     /// <returns>the number of bytes copied</returns>\r
132     public int CopyStored(StreamManipulator input, int len)\r
133     {\r
134       len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes);\r
135       int copied;\r
136 \r
137       int tailLen = WINDOW_SIZE - windowEnd;\r
138       if (len > tailLen)\r
139       {\r
140         copied = input.CopyBytes(window, windowEnd, tailLen);\r
141         if (copied == tailLen)\r
142         {\r
143           copied += input.CopyBytes(window, 0, len - tailLen);\r
144         }\r
145       }\r
146       else\r
147       {\r
148         copied = input.CopyBytes(window, windowEnd, len);\r
149       }\r
150 \r
151       windowEnd = (windowEnd + copied) & WINDOW_MASK;\r
152       windowFilled += copied;\r
153       return copied;\r
154     }\r
155 \r
156     /// <summary>\r
157     /// Copy dictionary to window\r
158     /// </summary>\r
159     /// <param name="dict">source dictionary</param>\r
160     /// <param name="offset">offset of start in source dictionary</param>\r
161     /// <param name="len">length of dictionary</param>\r
162     /// <exception cref="InvalidOperationException">\r
163     /// If window isnt empty\r
164     /// </exception>\r
165     public void CopyDict(byte[] dict, int offset, int len)\r
166     {\r
167       if (windowFilled > 0)\r
168       {\r
169         throw new InvalidOperationException();\r
170       }\r
171 \r
172       if (len > WINDOW_SIZE)\r
173       {\r
174         offset += len - WINDOW_SIZE;\r
175         len = WINDOW_SIZE;\r
176       }\r
177       System.Array.Copy(dict, offset, window, 0, len);\r
178       windowEnd = len & WINDOW_MASK;\r
179     }\r
180 \r
181     /// <summary>\r
182     /// Get remaining unfilled space in window\r
183     /// </summary>\r
184     /// <returns>Number of bytes left in window</returns>\r
185     public int GetFreeSpace()\r
186     {\r
187       return WINDOW_SIZE - windowFilled;\r
188     }\r
189 \r
190     /// <summary>\r
191     /// Get bytes available for output in window\r
192     /// </summary>\r
193     /// <returns>Number of bytes filled</returns>\r
194     public int GetAvailable()\r
195     {\r
196       return windowFilled;\r
197     }\r
198 \r
199     /// <summary>\r
200     /// Copy contents of window to output\r
201     /// </summary>\r
202     /// <param name="output">buffer to copy to</param>\r
203     /// <param name="offset">offset to start at</param>\r
204     /// <param name="len">number of bytes to count</param>\r
205     /// <returns>The number of bytes copied</returns>\r
206     /// <exception cref="InvalidOperationException">\r
207     /// If a window underflow occurs\r
208     /// </exception>\r
209     public int CopyOutput(byte[] output, int offset, int len)\r
210     {\r
211       int copy_end = windowEnd;\r
212       if (len > windowFilled)\r
213       {\r
214         len = windowFilled;\r
215       }\r
216       else\r
217       {\r
218         copy_end = (windowEnd - windowFilled + len) & WINDOW_MASK;\r
219       }\r
220 \r
221       int copied = len;\r
222       int tailLen = len - copy_end;\r
223 \r
224       if (tailLen > 0)\r
225       {\r
226         System.Array.Copy(window, WINDOW_SIZE - tailLen, output, offset, tailLen);\r
227         offset += tailLen;\r
228         len = copy_end;\r
229       }\r
230       System.Array.Copy(window, copy_end - len, output, offset, len);\r
231       windowFilled -= copied;\r
232       if (windowFilled < 0)\r
233       {\r
234         throw new InvalidOperationException();\r
235       }\r
236       return copied;\r
237     }\r
238 \r
239     /// <summary>\r
240     /// Reset by clearing window so <see cref="GetAvailable">GetAvailable</see> returns 0\r
241     /// </summary>\r
242     public void Reset()\r
243     {\r
244       windowFilled = windowEnd = 0;\r
245     }\r
246   }\r
247 }\r