blob: 62746b564a6aa3dd4abd4a4d45ddd0153fbee867 [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2021 MariaDB Corporation Ab
package org.mariadb.jdbc.client.impl;
import java.nio.charset.StandardCharsets;
import org.mariadb.jdbc.MariaDbBlob;
import org.mariadb.jdbc.client.ReadableByteBuf;
/** Packet buffer */
public final class StandardReadableByteBuf implements ReadableByteBuf {
/** row data limit */
private int limit;
/** buffer */
public byte[] buf;
/** current position reading buffer */
public int pos;
/**
* Packet buffer constructor
*
* @param buf buffer
* @param limit buffer limit
*/
public StandardReadableByteBuf(byte[] buf, int limit) {
this.pos = 0;
this.buf = buf;
this.limit = limit;
}
/**
* Packet buffer constructor, limit being the buffer length
*
* @param buf buffer
*/
public StandardReadableByteBuf(byte[] buf) {
this.pos = 0;
this.buf = buf;
this.limit = buf.length;
}
public int readableBytes() {
return limit - pos;
}
public int pos() {
return pos;
}
public byte[] buf() {
return buf;
}
public void buf(byte[] buf, int limit, int pos) {
this.buf = buf;
this.limit = limit;
this.pos = pos;
}
public void pos(int pos) {
this.pos = pos;
}
public void skip() {
pos++;
}
public void skip(int length) {
pos += length;
}
public void skipLengthEncoded() {
byte len = buf[pos++];
switch (len) {
case (byte) 251:
return;
case (byte) 252:
skip(readUnsignedShort());
return;
case (byte) 253:
skip(readUnsignedMedium());
return;
case (byte) 254:
skip((int) (4 + readUnsignedInt()));
return;
default:
pos += len & 0xff;
return;
}
}
public MariaDbBlob readBlob(int length) {
pos += length;
return MariaDbBlob.safeMariaDbBlob(buf, pos - length, length);
}
public long atoll(int length) {
boolean negate = false;
int idx = 0;
long result = 0;
if (length > 0 && buf[pos] == 45) { // minus sign
negate = true;
pos++;
idx++;
}
while (idx++ < length) {
result = result * 10 + buf[pos++] - 48;
}
return (negate) ? -1 * result : result;
}
public long atoull(int length) {
long result = 0;
for (int idx = 0; idx < length; idx++) {
result = result * 10 + buf[pos++] - 48;
}
return result;
}
public byte getByte() {
return buf[pos];
}
public byte getByte(int index) {
return buf[index];
}
public short getUnsignedByte() {
return (short) (buf[pos] & 0xff);
}
public long readLongLengthEncodedNotNull() {
int type = (buf[pos++] & 0xff);
if (type < 251) return type;
switch (type) {
case 252: // 0xfc
return readUnsignedShort();
case 253: // 0xfd
return readUnsignedMedium();
default: // 0xfe
return readLong();
}
}
public int readIntLengthEncodedNotNull() {
int type = (buf[pos++] & 0xff);
if (type < 251) return type;
switch (type) {
case 252:
return readUnsignedShort();
case 253:
return readUnsignedMedium();
case 254:
return (int) readLong();
default:
return type;
}
}
/**
* Identifier can have a max length of 256 (alias) So no need to check whole length encoding.
*
* @return current pos
*/
public int skipIdentifier() {
int len = readIntLengthEncodedNotNull();
pos += len;
return pos;
}
public Integer readLength() {
int type = readUnsignedByte();
switch (type) {
case 251:
return null;
case 252:
return readUnsignedShort();
case 253:
return readUnsignedMedium();
case 254:
return (int) readLong();
default:
return type;
}
}
public byte readByte() {
return buf[pos++];
}
public short readUnsignedByte() {
return (short) (buf[pos++] & 0xff);
}
public short readShort() {
return (short) ((buf[pos++] & 0xff) + (buf[pos++] << 8));
}
public int readUnsignedShort() {
return ((buf[pos++] & 0xff) + (buf[pos++] << 8)) & 0xffff;
}
public int readMedium() {
int value = readUnsignedMedium();
if ((value & 0x800000) != 0) {
value |= 0xff000000;
}
return value;
}
public int readUnsignedMedium() {
return ((buf[pos++] & 0xff) + ((buf[pos++] & 0xff) << 8) + ((buf[pos++] & 0xff) << 16));
}
public int readInt() {
return ((buf[pos++] & 0xff)
+ ((buf[pos++] & 0xff) << 8)
+ ((buf[pos++] & 0xff) << 16)
+ ((buf[pos++] & 0xff) << 24));
}
public int readIntBE() {
return (((buf[pos++] & 0xff) << 24)
+ ((buf[pos++] & 0xff) << 16)
+ ((buf[pos++] & 0xff) << 8)
+ (buf[pos++] & 0xff));
}
public long readUnsignedInt() {
return ((buf[pos++] & 0xff)
+ ((buf[pos++] & 0xff) << 8)
+ ((buf[pos++] & 0xff) << 16)
+ ((long) (buf[pos++] & 0xff) << 24))
& 0xffffffffL;
}
public long readLong() {
return ((buf[pos++] & 0xffL)
+ ((buf[pos++] & 0xffL) << 8)
+ ((buf[pos++] & 0xffL) << 16)
+ ((buf[pos++] & 0xffL) << 24)
+ ((buf[pos++] & 0xffL) << 32)
+ ((buf[pos++] & 0xffL) << 40)
+ ((buf[pos++] & 0xffL) << 48)
+ ((buf[pos++] & 0xffL) << 56));
}
public long readLongBE() {
return (((buf[pos++] & 0xffL) << 56)
+ ((buf[pos++] & 0xffL) << 48)
+ ((buf[pos++] & 0xffL) << 40)
+ ((buf[pos++] & 0xffL) << 32)
+ ((buf[pos++] & 0xffL) << 24)
+ ((buf[pos++] & 0xffL) << 16)
+ ((buf[pos++] & 0xffL) << 8)
+ (buf[pos++] & 0xffL));
}
public void readBytes(byte[] dst) {
System.arraycopy(buf, pos, dst, 0, dst.length);
pos += dst.length;
}
public byte[] readBytesNullEnd() {
int initialPosition = pos;
int cnt = 0;
while (readableBytes() > 0 && (buf[pos++] != 0)) {
cnt++;
}
byte[] dst = new byte[cnt];
System.arraycopy(buf, initialPosition, dst, 0, dst.length);
return dst;
}
public StandardReadableByteBuf readLengthBuffer() {
int len = this.readIntLengthEncodedNotNull();
byte[] tmp = new byte[len];
readBytes(tmp);
return new StandardReadableByteBuf(tmp, len);
}
public String readString(int length) {
pos += length;
return new String(buf, pos - length, length, StandardCharsets.UTF_8);
}
public String readAscii(int length) {
pos += length;
return new String(buf, pos - length, length, StandardCharsets.US_ASCII);
}
public String readStringNullEnd() {
int initialPosition = pos;
int cnt = 0;
while (readableBytes() > 0 && (buf[pos++] != 0)) {
cnt++;
}
return new String(buf, initialPosition, cnt, StandardCharsets.UTF_8);
}
public String readStringEof() {
int initialPosition = pos;
pos = limit;
return new String(buf, initialPosition, pos - initialPosition, StandardCharsets.UTF_8);
}
public float readFloat() {
return Float.intBitsToFloat(readInt());
}
public double readDouble() {
return Double.longBitsToDouble(readLong());
}
public double readDoubleBE() {
return Double.longBitsToDouble(readLongBE());
}
}