org.mariadb.jdbc.internal.com.read.Buffer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mariadb-java-client-jre7 Show documentation
Show all versions of mariadb-java-client-jre7 Show documentation
JDBC driver for MariaDB and MySQL for java 7
The newest version!
/*
*
* MariaDB Client for Java
*
* Copyright (c) 2012-2014 Monty Program Ab.
* Copyright (c) 2015-2017 MariaDB Ab.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this library; if not, write to Monty Program Ab [email protected].
*
* This particular MariaDB Client for Java file is work
* derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to
* the following copyright and notice provisions:
*
* Copyright (c) 2009-2011, Marcus Eriksson
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name of the driver nor the names of its contributors may not be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
package org.mariadb.jdbc.internal.com.read;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class Buffer {
public byte[] buf;
public int position;
public int limit;
public Buffer(final byte[] buf, int limit) {
this.buf = buf;
this.limit = limit;
}
/**
* Constructor with default limit and offset.
*
* @param buf byte array
*/
public Buffer(final byte[] buf) {
this.buf = buf;
this.limit = this.buf.length;
}
public int remaining() {
return limit - position;
}
/**
* Reads a string from the buffer, looks for a 0 to end the string.
*
* @param charset the charset to use, for example ASCII
* @return the read string
*/
public String readStringNullEnd(final Charset charset) {
int initialPosition = position;
int cnt = 0;
while (remaining() > 0 && (buf[position++] != 0)) {
cnt++;
}
return new String(buf, initialPosition, cnt, charset);
}
/**
* Reads a byte array from the buffer, looks for a 0 to end the array.
*
* @return the read array
*/
public byte[] readBytesNullEnd() {
int initialPosition = position;
int cnt = 0;
while (remaining() > 0 && (buf[position++] != 0)) {
cnt++;
}
final byte[] tmpArr = new byte[cnt];
System.arraycopy(buf, initialPosition, tmpArr, 0, cnt);
return tmpArr;
}
/**
* Reads length-encoded string.
*
* @param charset the charset to use, for example ASCII
* @return the read string
*/
public String readStringLengthEncoded(final Charset charset) {
int length = (int) getLengthEncodedNumeric();
String string = new String(buf, position, length, charset);
position += length;
return string;
}
/**
* Read a short (2 bytes) from the buffer.
*
* @return an short
*/
public short readShort() {
return (short) ((buf[position++] & 0xff)
+ ((buf[position++] & 0xff) << 8));
}
/**
* Read 24 bit integer.
*
* @return length
*/
public int read24bitword() {
return (buf[position++] & 0xff)
+ ((buf[position++] & 0xff) << 8)
+ ((buf[position++] & 0xff) << 16);
}
/**
* Read a int (4 bytes) from the buffer.
*
* @return a int
*/
public int readInt() {
return ((buf[position++] & 0xff)
+ ((buf[position++] & 0xff) << 8)
+ ((buf[position++] & 0xff) << 16)
+ ((buf[position++] & 0xff) << 24));
}
/**
* Read a long (8 bytes) from the buffer.
*
* @return a long
*/
public long readLong() {
return ((buf[position++] & 0xff)
+ ((long) (buf[position++] & 0xff) << 8)
+ ((long) (buf[position++] & 0xff) << 16)
+ ((long) (buf[position++] & 0xff) << 24)
+ ((long) (buf[position++] & 0xff) << 32)
+ ((long) (buf[position++] & 0xff) << 40)
+ ((long) (buf[position++] & 0xff) << 48)
+ ((long) (buf[position++] & 0xff) << 56));
}
/**
* Reads a byte from the buffer.
*
* @return the byte
*/
public byte readByte() {
return buf[position++];
}
/**
* Read raw data.
*
* @param numberOfBytes raw data length.
* @return raw data
*/
public byte[] readRawBytes(final int numberOfBytes) {
final byte[] tmpArr = new byte[numberOfBytes];
System.arraycopy(buf, position, tmpArr, 0, numberOfBytes);
position += numberOfBytes;
return tmpArr;
}
public void skipByte() {
position++;
}
public void skipBytes(final int bytesToSkip) {
position += bytesToSkip;
}
/**
* Skip next length encode binary data.
*/
public void skipLengthEncodedBytes() {
int type = this.buf[this.position++] & 0xff;
switch (type) {
case 251:
break;
case 252:
position += 2 + (0xffff & (((buf[position] & 0xff) + ((buf[position + 1] & 0xff) << 8))));
break;
case 253:
position += 3 + (0xffffff & ((buf[position] & 0xff)
+ ((buf[position + 1] & 0xff) << 8)
+ ((buf[position + 2] & 0xff) << 16)));
break;
case 254:
position += 8 + ((buf[position] & 0xff)
+ ((long) (buf[position + 1] & 0xff) << 8)
+ ((long) (buf[position + 2] & 0xff) << 16)
+ ((long) (buf[position + 3] & 0xff) << 24)
+ ((long) (buf[position + 4] & 0xff) << 32)
+ ((long) (buf[position + 5] & 0xff) << 40)
+ ((long) (buf[position + 6] & 0xff) << 48)
+ ((long) (buf[position + 7] & 0xff) << 56));
break;
default:
position += type;
}
}
/**
* Get next binary data length.
*
* @return length of next binary data
*/
public long getLengthEncodedNumeric() {
int type = this.buf[this.position++] & 0xff;
switch (type) {
case 251:
return -1;
case 252:
return 0xffff & readShort();
case 253:
return 0xffffff & read24bitword();
case 254:
return readLong();
default:
return type;
}
}
/**
* Get next data bytes from length encoded prefix.
*
* @return buffer
*/
public Buffer getLengthEncodedBuffer() {
return new Buffer(getLengthEncodedBytes());
}
/**
* Get next data bytes with length encoded prefix.
*
* @return the raw binary data
*/
public byte[] getLengthEncodedBytes() {
int type = this.buf[this.position++] & 0xff;
int length;
switch (type) {
case 251:
return null;
case 252:
length = 0xffff & readShort();
break;
case 253:
length = 0xffffff & read24bitword();
break;
case 254:
length = (int) ((buf[position++] & 0xff)
+ ((long) (buf[position++] & 0xff) << 8)
+ ((long) (buf[position++] & 0xff) << 16)
+ ((long) (buf[position++] & 0xff) << 24)
+ ((long) (buf[position++] & 0xff) << 32)
+ ((long) (buf[position++] & 0xff) << 40)
+ ((long) (buf[position++] & 0xff) << 48)
+ ((long) (buf[position++] & 0xff) << 56));
break;
default:
length = type;
}
byte[] tmpBuf = new byte[length];
System.arraycopy(buf, position, tmpBuf, 0, length);
position += length;
return tmpBuf;
}
public byte getByteAt(final int position) {
return buf[position];
}
/**
* Write value with length encoded prefix.
*
* @param value value to write
*/
public void writeStringLength(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
int length = bytes.length;
while (remaining() < length + 9) grow();
writeLength(length);
System.arraycopy(bytes, 0, buf, position, length);
position += length;
}
/**
* Write bytes.
*
* @param header header byte
* @param bytes command bytes
*/
public void writeBytes(byte header, byte[] bytes) {
int length = bytes.length;
while (remaining() < length + 10) grow();
writeLength(length + 1);
buf[position++] = header;
System.arraycopy(bytes, 0, buf, position, length);
position += length;
}
/**
* Write length.
*
* @param length length
*/
public void writeLength(long length) {
if (length < 251) {
buf[position++] = (byte) length;
} else if (length < 65536) {
buf[position++] = (byte) 0xfc;
buf[position++] = (byte) (length >>> 0);
buf[position++] = (byte) (length >>> 8);
} else if (length < 16777216) {
buf[position++] = (byte) 0xfd;
buf[position++] = (byte) (length >>> 0);
buf[position++] = (byte) (length >>> 8);
buf[position++] = (byte) (length >>> 16);
} else {
buf[position++] = (byte) 0xfe;
buf[position++] = (byte) (length >>> 0);
buf[position++] = (byte) (length >>> 8);
buf[position++] = (byte) (length >>> 16);
buf[position++] = (byte) (length >>> 24);
buf[position++] = (byte) (length >>> 32);
buf[position++] = (byte) (length >>> 40);
buf[position++] = (byte) (length >>> 48);
buf[position++] = (byte) (length >>> 54);
}
}
/**
* Grow data array.
*/
private void grow() {
int newCapacity = buf.length + (buf.length >> 1);
if (newCapacity - (Integer.MAX_VALUE - 8) > 0) newCapacity = Integer.MAX_VALUE - 8;
buf = Arrays.copyOf(buf, newCapacity);
this.limit = newCapacity;
}
}