1 /* CompressedInputStream.java --
2    Copyright (C) 2003, 2004  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.net.protocol.ftp;
40 
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.net.ProtocolException;
44 
45 /**
46  * A DTP input stream that implements the FTP compressed transfer mode.
47  *
48  * @author Chris Burdess (dog@gnu.org)
49  */
50 class CompressedInputStream
51   extends DTPInputStream
52 {
53 
54   static final int EOF = 64;
55 
56   static final int RAW = 0x00;
57   static final int COMPRESSED = 0x80;
58   static final int FILLER = 0xc0;
59 
60   int descriptor;
61   int max = -1;
62   int count = -1;
63 
64   int state = RAW;              // RAW | STATE | FILLER
65   int rep;                      // the compressed byte
66   int n = 0;                    // the number of compressed or raw bytes
67 
CompressedInputStream(DTP dtp, InputStream in)68   CompressedInputStream(DTP dtp, InputStream in)
69   {
70     super(dtp, in);
71   }
72 
read()73   public int read()
74     throws IOException
75   {
76     if (transferComplete)
77       {
78         return -1;
79       }
80     if (count == -1)
81       {
82         readHeader();
83       }
84     if (max < 1)
85       {
86         close();
87         return -1;
88       }
89     if (n > 0 && (state == COMPRESSED || state == FILLER))
90       {
91         n--;
92         return rep;
93       }
94     int c = in.read();
95     if (c == -1)
96       {
97         close();
98       }
99     count++;
100     if (count >= max)
101       {
102         count = -1;
103         if (descriptor == EOF)
104           {
105             close();
106           }
107       }
108     if (c == -1)
109       {
110         return c;
111       }
112     while (n == 0)              // read code header
113       {
114         state = (c & 0xc0);
115         n = (c & 0x3f);
116         c = in.read();
117         if (c == -1)
118           {
119             return -1;
120           }
121       }
122     switch (state)
123       {
124       case RAW:
125         break;
126       case COMPRESSED:
127       case FILLER:
128         rep = c;
129         break;
130       default:
131         throw new ProtocolException("Illegal state: " + state);
132       }
133     n--;
134     return c;
135   }
136 
read(byte[] buf)137   public int read(byte[] buf)
138     throws IOException
139   {
140     return read(buf, 0, buf.length);
141   }
142 
read(byte[] buf, int off, int len)143   public int read(byte[] buf, int off, int len)
144     throws IOException
145   {
146     if (transferComplete)
147       {
148         return -1;
149       }
150     if (count == -1)
151       {
152         readHeader();
153       }
154     if (max < 1)
155       {
156         close();
157         return -1;
158       }
159     // TODO improve performance
160     for (int i = off; i < len; i++)
161       {
162         int c = read();
163         if (c == -1)
164           {
165             close();
166             return i;
167           }
168         buf[i] = (byte) c;
169       }
170     return len;
171     /*
172        int l = in.read (buf, off, len);
173        if (l==-1)
174        {
175        close ();
176        }
177        count += l;
178        if (count>=max)
179        {
180        count = -1;
181        if (descriptor==EOF)
182        {
183        close ();
184        }
185        }
186        return l;
187      */
188   }
189 
190   /**
191    * Reads the block header.
192    */
readHeader()193   void readHeader()
194     throws IOException
195   {
196     descriptor = in.read();
197     int max_hi = in.read();
198     int max_lo = in.read();
199     max = (max_hi << 8) | max_lo;
200     count = 0;
201   }
202 
203   /**
204    * Reads the code header.
205    */
readCodeHeader()206   void readCodeHeader()
207     throws IOException
208   {
209     int code = in.read();
210     state = (code & 0xc0);
211     n = (code & 0x3f);
212   }
213 
214 }
215