Logo Search packages:      
Sourcecode: mysql-connector-java version File versions  Download package

Buffer.java

/*
 Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
 

  The MySQL Connector/J is licensed under the terms of the GPLv2
  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FLOSS License Exception
  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.

  This program is free software; you can redistribute it and/or modify it under the terms
  of the GNU General Public License as published by the Free Software Foundation; version 2
  of the License.

  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with this
  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  USA



 */
package com.mysql.jdbc;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.sql.SQLException;

/**
 * Buffer contains code to read and write packets from/to the MySQL server.
 * 
 * @version $Id$
 * @author Mark Matthews
 */
00038 public class Buffer {
      static final int MAX_BYTES_TO_DUMP = 512;

      static final int NO_LENGTH_LIMIT = -1;

      static final long NULL_LENGTH = -1;

      private int bufLength = 0;

      private byte[] byteBuffer;

      private int position = 0;

      protected boolean wasMultiPacket = false;

      Buffer(byte[] buf) {
            this.byteBuffer = buf;
            setBufLength(buf.length);
      }

      Buffer(int size) {
            this.byteBuffer = new byte[size];
            setBufLength(this.byteBuffer.length);
            this.position = MysqlIO.HEADER_LENGTH;
      }

      final void clear() {
            this.position = MysqlIO.HEADER_LENGTH;
      }

      final void dump() {
            dump(getBufLength());
      }

      final String dump(int numBytes) {
            return StringUtils.dumpAsHex(getBytes(0,
                        numBytes > getBufLength() ? getBufLength() : numBytes),
                        numBytes > getBufLength() ? getBufLength() : numBytes);
      }

      final String dumpClampedBytes(int numBytes) {
            int numBytesToDump = numBytes < MAX_BYTES_TO_DUMP ? numBytes
                        : MAX_BYTES_TO_DUMP;

            String dumped = StringUtils.dumpAsHex(getBytes(0,
                        numBytesToDump > getBufLength() ? getBufLength()
                                    : numBytesToDump),
                        numBytesToDump > getBufLength() ? getBufLength()
                                    : numBytesToDump);

            if (numBytesToDump < numBytes) {
                  return dumped + " ....(packet exceeds max. dump length)";
            }

            return dumped;
      }

      final void dumpHeader() {
            for (int i = 0; i < MysqlIO.HEADER_LENGTH; i++) {
                  String hexVal = Integer.toHexString(readByte(i) & 0xff);

                  if (hexVal.length() == 1) {
                        hexVal = "0" + hexVal; //$NON-NLS-1$
                  }

                  System.out.print(hexVal + " "); //$NON-NLS-1$
            }
      }

      final void dumpNBytes(int start, int nBytes) {
            StringBuffer asciiBuf = new StringBuffer();

            for (int i = start; (i < (start + nBytes)) && (i < getBufLength()); i++) {
                  String hexVal = Integer.toHexString(readByte(i) & 0xff);

                  if (hexVal.length() == 1) {
                        hexVal = "0" + hexVal; //$NON-NLS-1$
                  }

                  System.out.print(hexVal + " "); //$NON-NLS-1$

                  if ((readByte(i) > 32) && (readByte(i) < 127)) {
                        asciiBuf.append((char) readByte(i));
                  } else {
                        asciiBuf.append("."); //$NON-NLS-1$
                  }

                  asciiBuf.append(" "); //$NON-NLS-1$
            }

            System.out.println("    " + asciiBuf.toString()); //$NON-NLS-1$
      }

      final void ensureCapacity(int additionalData) throws SQLException {
            if ((this.position + additionalData) > getBufLength()) {
                  if ((this.position + additionalData) < this.byteBuffer.length) {
                        // byteBuffer.length is != getBufLength() all of the time
                        // due to re-using of packets (we don't shrink them)
                        //
                        // If we can, don't re-alloc, just set buffer length
                        // to size of current buffer
                        setBufLength(this.byteBuffer.length);
                  } else {
                        //
                        // Otherwise, re-size, and pad so we can avoid
                        // allocing again in the near future
                        //
                        int newLength = (int) (this.byteBuffer.length * 1.25);

                        if (newLength < (this.byteBuffer.length + additionalData)) {
                              newLength = this.byteBuffer.length
                                          + (int) (additionalData * 1.25);
                        }

                        if (newLength < this.byteBuffer.length) {
                              newLength = this.byteBuffer.length + additionalData;
                        }

                        byte[] newBytes = new byte[newLength];

                        System.arraycopy(this.byteBuffer, 0, newBytes, 0,
                                    this.byteBuffer.length);
                        this.byteBuffer = newBytes;
                        setBufLength(this.byteBuffer.length);
                  }
            }
      }

      /**
       * Skip over a length-encoded string
       * 
       * @return The position past the end of the string
       */
00171       public int fastSkipLenString() {
            long len = this.readFieldLength();

            this.position += len;

            return (int) len;
      }

      public void fastSkipLenByteArray() {
            long len = this.readFieldLength();

            if (len == NULL_LENGTH || len == 0) {
                  return;
            }
            
            this.position += len;
      }
      
      protected final byte[] getBufferSource() {
            return this.byteBuffer;
      }

      int getBufLength() {
            return this.bufLength;
      }

      /**
       * Returns the array of bytes this Buffer is using to read from.
       * 
       * @return byte array being read from
       */
00202       public byte[] getByteBuffer() {
            return this.byteBuffer;
      }

      final byte[] getBytes(int len) {
            byte[] b = new byte[len];
            System.arraycopy(this.byteBuffer, this.position, b, 0, len);
            this.position += len; // update cursor

            return b;
      }

      /*
       * (non-Javadoc)
       * 
       * @see com.mysql.jdbc.Buffer#getBytes(int, int)
       */
      byte[] getBytes(int offset, int len) {
            byte[] dest = new byte[len];
            System.arraycopy(this.byteBuffer, offset, dest, 0, len);

            return dest;
      }

      int getCapacity() {
            return this.byteBuffer.length;
      }

      public ByteBuffer getNioBuffer() {
            throw new IllegalArgumentException(Messages
                        .getString("ByteArrayBuffer.0")); //$NON-NLS-1$
      }

      /**
       * Returns the current position to write to/ read from
       * 
       * @return the current position to write to/ read from
       */
00240       public int getPosition() {
            return this.position;
      }

      // 2000-06-05 Changed
      final boolean isLastDataPacket() {
            return ((getBufLength() < 9) && ((this.byteBuffer[0] & 0xff) == 254));
      }

      final long newReadLength() {
            int sw = this.byteBuffer[this.position++] & 0xff;

            switch (sw) {
            case 251:
                  return 0;

            case 252:
                  return readInt();

            case 253:
                  return readLongInt();

            case 254: // changed for 64 bit lengths
                  return readLongLong();

            default:
                  return sw;
            }
      }

      final byte readByte() {
            return this.byteBuffer[this.position++];
      }

      final byte readByte(int readAt) {
            return this.byteBuffer[readAt];
      }

      final long readFieldLength() {
            int sw = this.byteBuffer[this.position++] & 0xff;

            switch (sw) {
            case 251:
                  return NULL_LENGTH;

            case 252:
                  return readInt();

            case 253:
                  return readLongInt();

            case 254:
                  return readLongLong();

            default:
                  return sw;
            }
      }

      // 2000-06-05 Changed
      final int readInt() {
            byte[] b = this.byteBuffer; // a little bit optimization

            return (b[this.position++] & 0xff) | ((b[this.position++] & 0xff) << 8);
      }

      final int readIntAsLong() {
            byte[] b = this.byteBuffer;

            return (b[this.position++] & 0xff) | ((b[this.position++] & 0xff) << 8)
                        | ((b[this.position++] & 0xff) << 16)
                        | ((b[this.position++] & 0xff) << 24);
      }

      final byte[] readLenByteArray(int offset) {
            long len = this.readFieldLength();

            if (len == NULL_LENGTH) {
                  return null;
            }

            if (len == 0) {
                  return Constants.EMPTY_BYTE_ARRAY;
            }

            this.position += offset;

            return getBytes((int) len);
      }

      final long readLength() {
            int sw = this.byteBuffer[this.position++] & 0xff;

            switch (sw) {
            case 251:
                  return 0;

            case 252:
                  return readInt();

            case 253:
                  return readLongInt();

            case 254:
                  return readLong();

            default:
                  return sw;
            }
      }

      // 2000-06-05 Fixed
      final long readLong() {
            byte[] b = this.byteBuffer;

            return ((long) b[this.position++] & 0xff)
                        | (((long) b[this.position++] & 0xff) << 8)
                        | ((long) (b[this.position++] & 0xff) << 16)
                        | ((long) (b[this.position++] & 0xff) << 24);
      }

      // 2000-06-05 Changed
      final int readLongInt() {
            byte[] b = this.byteBuffer;

            return (b[this.position++] & 0xff) | ((b[this.position++] & 0xff) << 8)
                        | ((b[this.position++] & 0xff) << 16);
      }

      // 2000-06-05 Fixed
      final long readLongLong() {
            byte[] b = this.byteBuffer;

            return (b[this.position++] & 0xff)
                        | ((long) (b[this.position++] & 0xff) << 8)
                        | ((long) (b[this.position++] & 0xff) << 16)
                        | ((long) (b[this.position++] & 0xff) << 24)
                        | ((long) (b[this.position++] & 0xff) << 32)
                        | ((long) (b[this.position++] & 0xff) << 40)
                        | ((long) (b[this.position++] & 0xff) << 48)
                        | ((long) (b[this.position++] & 0xff) << 56);
      }

      final int readnBytes() {
            int sw = this.byteBuffer[this.position++] & 0xff;

            switch (sw) {
            case 1:
                  return this.byteBuffer[this.position++] & 0xff;

            case 2:
                  return this.readInt();

            case 3:
                  return this.readLongInt();

            case 4:
                  return (int) this.readLong();

            default:
                  return 255;
            }
      }

      //
      // Read a null-terminated string
      //
      // To avoid alloc'ing a new byte array, we
      // do this by hand, rather than calling getNullTerminatedBytes()
      //
      final String readString() {
            int i = this.position;
            int len = 0;
            int maxLen = getBufLength();

            while ((i < maxLen) && (this.byteBuffer[i] != 0)) {
                  len++;
                  i++;
            }

            String s = new String(this.byteBuffer, this.position, len);
            this.position += (len + 1); // update cursor

            return s;
      }

      final String readString(String encoding, ExceptionInterceptor exceptionInterceptor) throws SQLException {
            int i = this.position;
            int len = 0;
            int maxLen = getBufLength();

            while ((i < maxLen) && (this.byteBuffer[i] != 0)) {
                  len++;
                  i++;
            }

            try {
                  return new String(this.byteBuffer, this.position, len, encoding);
            } catch (UnsupportedEncodingException uEE) {
                  throw SQLError.createSQLException(Messages.getString("ByteArrayBuffer.1") //$NON-NLS-1$
                              + encoding + "'", SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor); //$NON-NLS-1$
            } finally {
                  this.position += (len + 1); // update cursor
            }
      }

      void setBufLength(int bufLengthToSet) {
            this.bufLength = bufLengthToSet;
      }

      /**
       * Sets the array of bytes to use as a buffer to read from.
       * 
       * @param byteBuffer
       *            the array of bytes to use as a buffer
       */
00456       public void setByteBuffer(byte[] byteBufferToSet) {
            this.byteBuffer = byteBufferToSet;
      }

      /**
       * Set the current position to write to/ read from
       * 
       * @param position
       *            the position (0-based index)
       */
00466       public void setPosition(int positionToSet) {
            this.position = positionToSet;
      }

      /**
       * Sets whether this packet was part of a multipacket
       * 
       * @param flag
       *            was this packet part of a multipacket?
       */
00476       public void setWasMultiPacket(boolean flag) {
            this.wasMultiPacket = flag;
      }

      public String toString() {
            return dumpClampedBytes(getPosition());
      }

      public String toSuperString() {
            return super.toString();
      }

      /**
       * Was this packet part of a multipacket?
       * 
       * @return was this packet part of a multipacket?
       */
00493       public boolean wasMultiPacket() {
            return this.wasMultiPacket;
      }

      final void writeByte(byte b) throws SQLException {
            ensureCapacity(1);

            this.byteBuffer[this.position++] = b;
      }

      // Write a byte array
      final void writeBytesNoNull(byte[] bytes) throws SQLException {
            int len = bytes.length;
            ensureCapacity(len);
            System.arraycopy(bytes, 0, this.byteBuffer, this.position, len);
            this.position += len;
      }

      // Write a byte array with the given offset and length
      final void writeBytesNoNull(byte[] bytes, int offset, int length)
                  throws SQLException {
            ensureCapacity(length);
            System.arraycopy(bytes, offset, this.byteBuffer, this.position, length);
            this.position += length;
      }

      final void writeDouble(double d) throws SQLException {
            long l = Double.doubleToLongBits(d);
            writeLongLong(l);
      }

      final void writeFieldLength(long length) throws SQLException {
            if (length < 251) {
                  writeByte((byte) length);
            } else if (length < 65536L) {
                  ensureCapacity(3);
                  writeByte((byte) 252);
                  writeInt((int) length);
            } else if (length < 16777216L) {
                  ensureCapacity(4);
                  writeByte((byte) 253);
                  writeLongInt((int) length);
            } else {
                  ensureCapacity(9);
                  writeByte((byte) 254);
                  writeLongLong(length);
            }
      }

      final void writeFloat(float f) throws SQLException {
            ensureCapacity(4);

            int i = Float.floatToIntBits(f);
            byte[] b = this.byteBuffer;
            b[this.position++] = (byte) (i & 0xff);
            b[this.position++] = (byte) (i >>> 8);
            b[this.position++] = (byte) (i >>> 16);
            b[this.position++] = (byte) (i >>> 24);
      }

      // 2000-06-05 Changed
      final void writeInt(int i) throws SQLException {
            ensureCapacity(2);

            byte[] b = this.byteBuffer;
            b[this.position++] = (byte) (i & 0xff);
            b[this.position++] = (byte) (i >>> 8);
      }

      // Write a String using the specified character
      // encoding
      final void writeLenBytes(byte[] b) throws SQLException {
            int len = b.length;
            ensureCapacity(len + 9);
            writeFieldLength(len);
            System.arraycopy(b, 0, this.byteBuffer, this.position, len);
            this.position += len;
      }

      // Write a String using the specified character
      // encoding
      final void writeLenString(String s, String encoding, String serverEncoding,
                  SingleByteCharsetConverter converter, boolean parserKnowsUnicode,
                  MySQLConnection conn)
                  throws UnsupportedEncodingException, SQLException {
            byte[] b = null;

            if (converter != null) {
                  b = converter.toBytes(s);
            } else {
                  b = StringUtils.getBytes(s, encoding, serverEncoding,
                              parserKnowsUnicode, conn, conn.getExceptionInterceptor());
            }

            int len = b.length;
            ensureCapacity(len + 9);
            writeFieldLength(len);
            System.arraycopy(b, 0, this.byteBuffer, this.position, len);
            this.position += len;
      }

      // 2000-06-05 Changed
      final void writeLong(long i) throws SQLException {
            ensureCapacity(4);

            byte[] b = this.byteBuffer;
            b[this.position++] = (byte) (i & 0xff);
            b[this.position++] = (byte) (i >>> 8);
            b[this.position++] = (byte) (i >>> 16);
            b[this.position++] = (byte) (i >>> 24);
      }

      // 2000-06-05 Changed
      final void writeLongInt(int i) throws SQLException {
            ensureCapacity(3);
            byte[] b = this.byteBuffer;
            b[this.position++] = (byte) (i & 0xff);
            b[this.position++] = (byte) (i >>> 8);
            b[this.position++] = (byte) (i >>> 16);
      }

      final void writeLongLong(long i) throws SQLException {
            ensureCapacity(8);
            byte[] b = this.byteBuffer;
            b[this.position++] = (byte) (i & 0xff);
            b[this.position++] = (byte) (i >>> 8);
            b[this.position++] = (byte) (i >>> 16);
            b[this.position++] = (byte) (i >>> 24);
            b[this.position++] = (byte) (i >>> 32);
            b[this.position++] = (byte) (i >>> 40);
            b[this.position++] = (byte) (i >>> 48);
            b[this.position++] = (byte) (i >>> 56);
      }

      // Write null-terminated string
      final void writeString(String s) throws SQLException {
            ensureCapacity((s.length() * 2) + 1);
            writeStringNoNull(s);
            this.byteBuffer[this.position++] = 0;
      }
      
      //     Write null-terminated string in the given encoding
      final void writeString(String s, String encoding, MySQLConnection conn) throws SQLException {
            ensureCapacity((s.length() * 2) + 1);
            try {
                  writeStringNoNull(s, encoding, encoding, false, conn);
            } catch (UnsupportedEncodingException ue) {
                  throw new SQLException(ue.toString(), SQLError.SQL_STATE_GENERAL_ERROR);
            }
            
            this.byteBuffer[this.position++] = 0;
      }

      // Write string, with no termination
      final void writeStringNoNull(String s) throws SQLException {
            int len = s.length();
            ensureCapacity(len * 2);
            System.arraycopy(s.getBytes(), 0, this.byteBuffer, this.position, len);
            this.position += len;

            // for (int i = 0; i < len; i++)
            // {
            // this.byteBuffer[this.position++] = (byte)s.charAt(i);
            // }
      }

      // Write a String using the specified character
      // encoding
      final void writeStringNoNull(String s, String encoding,
                  String serverEncoding, boolean parserKnowsUnicode, MySQLConnection conn)
                  throws UnsupportedEncodingException, SQLException {
            byte[] b = StringUtils.getBytes(s, encoding, serverEncoding,
                        parserKnowsUnicode, conn, conn.getExceptionInterceptor());

            int len = b.length;
            ensureCapacity(len);
            System.arraycopy(b, 0, this.byteBuffer, this.position, len);
            this.position += len;
      }
}

Generated by  Doxygen 1.6.0   Back to index