Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/mysql/jdbc/CompressedInputStream.java


1   /*
2    Copyright (C) 2002-2004 MySQL AB
3   
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of version 2 of the GNU General Public License as
6    published by the Free Software Foundation.
7    
8   
9    There are special exceptions to the terms and conditions of the GPL 
10   as it is applied to this software. View the full text of the 
11   exception exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
12   software distribution.
13  
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18  
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23  */
24  package com.mysql.jdbc;
25  
26  import java.io.EOFException;
27  import java.io.IOException;
28  import java.io.InputStream;
29  
30  import java.util.zip.DataFormatException;
31  import java.util.zip.Inflater;
32  
33  
34  /**
35  * Used to de-compress packets from the MySQL server when protocol-level
36  * compression is turned on.
37  * 
38  * @author Mark Matthews
39  * 
40  * @version $Id: CompressedInputStream.java,v 1.1.4.5 2004/08/09 22:15:11 mmatthew Exp $
41  */
42  class CompressedInputStream extends InputStream {
43  
44   /** The ZIP inflater used to un-compress packets */
45   private Inflater inflater;
46  
47   /** The stream we are reading from the server */
48   private InputStream in;
49  
50   /** The packet data after it has been un-compressed */
51   private byte[] buffer;
52  
53   /** The position we are reading from */
54   private int pos = 0;
55   
56   /**
57    * The buffer to read packet headers into
58    */
59   private byte[] packetHeaderBuffer = new byte[7];
60  
61   /**
62    * Creates a new CompressedInputStream that reads the given stream from the
63    * server.
64    *
65    * @param conn DOCUMENT ME!
66    * @param streamFromServer
67    */
68   public CompressedInputStream(InputStream streamFromServer) {
69       this.in = streamFromServer;
70       this.inflater = new Inflater();
71   }
72  
73   /**
74    * @see java.io.InputStream#available()
75    */
76   public int available() throws IOException {
77       if (this.buffer == null) {
78           return this.in.available();
79       }
80  
81       return this.buffer.length - this.pos + this.in.available();
82   }
83  
84   /**
85    * @see java.io.InputStream#close()
86    */
87   public void close() throws IOException {
88       this.in.close();
89       this.buffer = null;
90       this.inflater = null;
91   }
92  
93   /**
94    * @see java.io.InputStream#read()
95    */
96   public int read() throws IOException {
97       try {
98           getNextPacketIfRequired(1);
99       } catch (IOException ioEx) {
100          return -1;
101      }
102 
103      return this.buffer[this.pos++] & 0xff;
104  }
105 
106  /**
107   * @see java.io.InputStream#read(byte, int, int)
108   */
109  public int read(byte[] b, int off, int len) throws IOException {
110      if (b == null) {
111          throw new NullPointerException();
112      } else if ((off < 0) || (off > b.length) || (len < 0)
113              || ((off + len) > b.length) || ((off + len) < 0)) {
114          throw new IndexOutOfBoundsException();
115      }
116 
117      if (len <= 0) {
118          return 0;
119      }
120 
121      try {
122          getNextPacketIfRequired(len);
123      } catch (IOException ioEx) {
124          return -1;
125      }
126 
127      System.arraycopy(this.buffer, this.pos, b, off, len);
128      this.pos += len;
129 
130      return len;
131  }
132 
133  /**
134   * @see java.io.InputStream#read(byte)
135   */
136  public int read(byte[] b) throws IOException {
137      return read(b, 0, b.length);
138  }
139 
140  /**
141   * @see java.io.InputStream#skip(long)
142   */
143  public long skip(long n) throws IOException {
144      long count = 0;
145 
146      for (long i = 0; i < n; i++) {
147          int bytesRead = read();
148 
149          if (bytesRead == -1) {
150              break;
151          }
152 
153          count++;
154      }
155 
156      return count;
157  }
158 
159  /**
160   * Retrieves and un-compressed (if necessary) the next packet from the
161   * server.
162   *
163   * @throws IOException if an I/O error occurs
164   */
165  private void getNextPacketFromServer() throws IOException {
166      byte[] uncompressedData = null;
167 
168      int lengthRead = readFully(this.packetHeaderBuffer, 0,
169              7);
170 
171      if (lengthRead < 7) {
172          throw new IOException("Unexpected end of input stream");
173      }
174 
175      int compressedPacketLength = ((int) (this.packetHeaderBuffer[0] & 0xff))
176          + (((int) (this.packetHeaderBuffer[1] & 0xff)) << 8)
177          + (((int) (this.packetHeaderBuffer[2] & 0xff)) << 16);
178       
179      int uncompressedLength = ((int) (this.packetHeaderBuffer[4] & 0xff))
180          + (((int) (this.packetHeaderBuffer[5] & 0xff)) << 8)
181          + (((int) (this.packetHeaderBuffer[6] & 0xff)) << 16);
182      
183      if (uncompressedLength > 0) {
184          uncompressedData = new byte[uncompressedLength];
185 
186          byte[] compressedBuffer = new byte[compressedPacketLength];
187 
188          readFully(compressedBuffer, 0, compressedPacketLength);
189 
190          try {
191              this.inflater.reset();
192          } catch (NullPointerException npe) {
193              this.inflater = new Inflater();
194          }
195 
196          this.inflater.setInput(compressedBuffer);
197 
198          try {
199              this.inflater.inflate(uncompressedData);
200          } catch (DataFormatException dfe) {
201              throw new IOException(
202                  "Error while uncompressing packet from server.");
203          }
204 
205          this.inflater.end();
206      } else {
207         
208          //  
209          //  Read data, note this this code is reached when using
210          //  compressed packets that have not been compressed, as well
211          //
212          uncompressedData = new byte[compressedPacketLength];
213          readFully(uncompressedData, 0, compressedPacketLength);
214      }
215 
216      if ((this.buffer != null) && (this.pos < this.buffer.length)) {
217          
218          int remaining = buffer.length - this.pos;
219          byte[] newBuffer = new byte[remaining + uncompressedData.length];
220 
221          int newIndex = 0;
222 
223          for (int i = this.pos; i < this.buffer.length; i++)
224              newBuffer[newIndex++] = this.buffer[i];
225 
226          System.arraycopy(uncompressedData, 0, newBuffer, newIndex,
227              uncompressedData.length);
228 
229          uncompressedData = newBuffer; 
230      }
231      
232      this.pos = 0;
233      this.buffer = uncompressedData;
234 
235      return;
236  }
237 
238  /**
239   * Determines if another packet needs to be read from the server to be able
240   * to read numBytes from the stream.
241   *
242   * @param numBytes the number of bytes to be read
243   *
244   * @throws IOException if an I/O error occors.
245   */
246  private void getNextPacketIfRequired(int numBytes)
247      throws IOException {
248      if ((this.buffer == null)
249              || ((this.pos + numBytes) > this.buffer.length)) {
250          getNextPacketFromServer();
251      }
252  }
253 
254  private final int readFully(byte[] b, int off, int len)
255      throws IOException {
256      if (len < 0) {
257          throw new IndexOutOfBoundsException();
258      }
259 
260      int n = 0;
261 
262      while (n < len) {
263          int count = this.in.read(b, off + n, len - n);
264 
265          if (count < 0) {
266              throw new EOFException();
267          }
268 
269          n += count;
270      }
271 
272      return n;
273  }
274 }