Skip to content

Instantly share code, notes, and snippets.

@devinrsmith
Created November 14, 2014 17:20
Show Gist options
  • Save devinrsmith/627573047e4e2884836f to your computer and use it in GitHub Desktop.
Save devinrsmith/627573047e4e2884836f to your computer and use it in GitHub Desktop.
FixedInput allows the same byte[] to be passed into Input.
import com.esotericsoftware.kryo.io.Input;
import java.io.InputStream;
/**
* Created by dsmith on 11/14/14.
*
* In reference to https://github.com/EsotericSoftware/kryo/issues/264
*/
public class FixedInput extends Input {
public FixedInput() {
}
public FixedInput(int bufferSize) {
super(bufferSize);
}
public FixedInput(byte[] buffer) {
super(buffer);
}
public FixedInput(byte[] buffer, int offset, int count) {
super(buffer, offset, count);
}
public FixedInput(InputStream inputStream) {
super(inputStream);
}
public FixedInput(InputStream inputStream, int bufferSize) {
super(inputStream, bufferSize);
}
@Override
public String readString() {
int available = require(1);
int b = buffer[position++];
if ((b & 0x80) == 0) return fixedReadAscii(); // ASCII.
// Null, empty, or UTF8.
int charCount = available >= 5 ? copy_readUtf8Length(b) : copy_readUtf8Length_slow(b);
switch (charCount) {
case 0:
return null;
case 1:
return "";
}
charCount--;
if (chars.length < charCount) chars = new char[charCount];
copy_readUtf8(charCount);
return new String(chars, 0, charCount);
}
private String fixedReadAscii () {
byte[] buffer = this.buffer;
int end = position;
int start = end - 1;
int limit = this.limit;
int b;
do {
if (end == limit) return copy_readAscii_slow();
b = buffer[end++];
} while ((b & 0x80) == 0);
// if we were really cared about the extra copy here, we could do the String work of
// copying buffer into a char[] and call the package private constructor via reflection
final int L = end - start;
final byte[] asciiBuffer = new byte[L];
System.arraycopy(buffer, start, asciiBuffer, 0, L);
asciiBuffer[L - 1] &= 0x7F;
String value = new String(asciiBuffer, 0, 0, L);
position = end;
return value;
}
// can't call private methods, so all the following copy_ methods are copied directly from Input
private String copy_readAscii_slow () {
position--; // Re-read the first byte.
// Copy chars currently in buffer.
int charCount = limit - position;
if (charCount > chars.length) chars = new char[charCount * 2];
char[] chars = this.chars;
byte[] buffer = this.buffer;
for (int i = position, ii = 0, n = limit; i < n; i++, ii++)
chars[ii] = (char)buffer[i];
position = limit;
// Copy additional chars one by one.
while (true) {
require(1);
int b = buffer[position++];
if (charCount == chars.length) {
char[] newChars = new char[charCount * 2];
System.arraycopy(chars, 0, newChars, 0, charCount);
chars = newChars;
this.chars = newChars;
}
if ((b & 0x80) == 0x80) {
chars[charCount++] = (char)(b & 0x7F);
break;
}
chars[charCount++] = (char)b;
}
return new String(chars, 0, charCount);
}
private int copy_readUtf8Length (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private int copy_readUtf8Length_slow (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
require(1);
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private void copy_readUtf8 (int charCount) {
byte[] buffer = this.buffer;
char[] chars = this.chars;
// Try to read 7 bit ASCII chars.
int charIndex = 0;
int count = Math.min(require(1), charCount);
int position = this.position;
int b;
while (charIndex < count) {
b = buffer[position++];
if (b < 0) {
position--;
break;
}
chars[charIndex++] = (char)b;
}
this.position = position;
// If buffer didn't hold all chars or any were not ASCII, use slow path for remainder.
if (charIndex < charCount) copy_readUtf8_slow(charCount, charIndex);
}
private void copy_readUtf8_slow (int charCount, int charIndex) {
char[] chars = this.chars;
byte[] buffer = this.buffer;
while (charIndex < charCount) {
if (position == limit) require(1);
int b = buffer[position++] & 0xFF;
switch (b >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
chars[charIndex] = (char)b;
break;
case 12:
case 13:
if (position == limit) require(1);
chars[charIndex] = (char)((b & 0x1F) << 6 | buffer[position++] & 0x3F);
break;
case 14:
require(2);
chars[charIndex] = (char)((b & 0x0F) << 12 | (buffer[position++] & 0x3F) << 6 | buffer[position++] & 0x3F);
break;
}
charIndex++;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment