Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hazelcast.nio.UTFEncoderDecoder Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2013, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.nio;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public final class UTFEncoderDecoder {
private static final int STRING_CHUNK_SIZE = 16 * 1024;
private static final UTFEncoderDecoder INSTANCE;
static {
INSTANCE = buildUTFUtil();
}
private final StringCreator stringCreator;
private final boolean hazelcastEnterpriseActive;
private UTFEncoderDecoder(boolean fastStringCreator) {
this(fastStringCreator ? buildFastStringCreator() : new DefaultStringCreator(), false);
}
private UTFEncoderDecoder(StringCreator stringCreator, boolean hazelcastEnterpriseActive) {
this.stringCreator = stringCreator;
this.hazelcastEnterpriseActive = hazelcastEnterpriseActive;
}
public StringCreator getStringCreator() {
return stringCreator;
}
public static void writeUTF(final DataOutput out, final String str, byte[] buffer) throws IOException {
INSTANCE.writeUTF0(out, str, buffer);
}
public static String readUTF(final DataInput in, byte[] buffer) throws IOException {
return INSTANCE.readUTF0(in, buffer);
}
public boolean isHazelcastEnterpriseActive() {
return hazelcastEnterpriseActive;
}
public void writeUTF0(final DataOutput out, final String str, byte[] buffer) throws IOException {
boolean isNull = str == null;
out.writeBoolean(isNull);
if (isNull) {
return;
}
int length = str.length();
out.writeInt(length);
if (length > 0) {
int chunkSize = (length / STRING_CHUNK_SIZE) + 1;
for (int i = 0; i < chunkSize; i++) {
int beginIndex = Math.max(0, i * STRING_CHUNK_SIZE - 1);
int endIndex = Math.min((i + 1) * STRING_CHUNK_SIZE - 1, length);
writeShortUTF(out, str, beginIndex, endIndex, buffer);
}
}
}
private void writeShortUTF(final DataOutput out,
final String str,
final int beginIndex,
final int endIndex,
byte[] buffer) throws IOException {
int utfLength = 0;
int c = 0;
int count = 0;
/* use charAt instead of copying String to char array */
for (int i = beginIndex; i < endIndex; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
utfLength++;
} else if (c > 0x07FF) {
utfLength += 3;
} else {
utfLength += 2;
}
}
if (utfLength > 65535) {
throw new UTFDataFormatException("encoded string too long:"
+ utfLength + " bytes");
}
out.writeShort(utfLength);
int i;
for (i = beginIndex; i < endIndex; i++) {
c = str.charAt(i);
if (!((c >= 0x0001) && (c <= 0x007F))) {
break;
}
buffering(buffer, count++, (byte) c, out);
}
for (; i < endIndex; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
buffering(buffer, count++, (byte) c, out);
} else if (c > 0x07FF) {
buffering(buffer, count++, (byte) (0xE0 | ((c >> 12) & 0x0F)), out);
buffering(buffer, count++, (byte) (0x80 | ((c >> 6) & 0x3F)), out);
buffering(buffer, count++, (byte) (0x80 | ((c) & 0x3F)), out);
} else {
buffering(buffer, count++, (byte) (0xC0 | ((c >> 6) & 0x1F)), out);
buffering(buffer, count++, (byte) (0x80 | ((c) & 0x3F)), out);
}
}
int length = count % buffer.length;
out.write(buffer, 0, length == 0 ? buffer.length : length);
}
public String readUTF0(final DataInput in, byte[] buffer) throws IOException {
boolean isNull = in.readBoolean();
if (isNull) {
return null;
}
int length = in.readInt();
final char[] data = new char[length];
if (length > 0) {
int chunkSize = length / STRING_CHUNK_SIZE + 1;
for (int i = 0; i < chunkSize; i++) {
int beginIndex = Math.max(0, i * STRING_CHUNK_SIZE - 1);
int endIndex = Math.min((i + 1) * STRING_CHUNK_SIZE - 1, length);
readShortUTF(in, data, beginIndex, endIndex, buffer);
}
}
return stringCreator.buildString(data);
}
private void readShortUTF(final DataInput in, final char[] data,
final int beginIndex, final int endIndex,
byte[] buffer) throws IOException {
final int utflen = in.readShort();
int c = 0;
int char2 = 0;
int char3 = 0;
int count = 0;
int charArrCount = beginIndex;
int lastCount = -1;
while (count < utflen) {
c = buffered(buffer, count, utflen, in) & 0xff;
if (c > 127) {
break;
}
lastCount = count;
count++;
data[charArrCount++] = (char) c;
}
while (count < utflen) {
if (lastCount > -1 && lastCount < count) {
c = buffered(buffer, count, utflen, in) & 0xff;
}
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
/* 0xxxxxxx */
lastCount = count;
count++;
data[charArrCount++] = (char) c;
break;
case 12:
case 13:
/* 110x xxxx 10xx xxxx */
lastCount = count++;
if (count + 1 > utflen) {
throw new UTFDataFormatException("malformed input: partial character at end");
}
char2 = buffered(buffer, count++, utflen, in);
if ((char2 & 0xC0) != 0x80) {
throw new UTFDataFormatException("malformed input around byte " + count);
}
data[charArrCount++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
/* 1110 xxxx 10xx xxxx 10xx xxxx */
lastCount = count++;
if (count + 2 > utflen) {
throw new UTFDataFormatException("malformed input: partial character at end");
}
char2 = buffered(buffer, count++, utflen, in);
char3 = buffered(buffer, count++, utflen, in);
if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
throw new UTFDataFormatException("malformed input around byte " + (count - 1));
}
data[charArrCount++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
break;
default:
/* 10xx xxxx, 1111 xxxx */
throw new UTFDataFormatException("malformed input around byte " + count);
}
}
}
private void buffering(byte[] buffer, int pos, byte value, DataOutput out) throws IOException {
int innerPos = pos % buffer.length;
if (pos > 0 && innerPos == 0) {
out.write(buffer, 0, buffer.length);
}
buffer[innerPos] = value;
}
private byte buffered(byte[] buffer, int pos, int utfLenght, DataInput in) throws IOException {
int innerPos = pos % buffer.length;
if (innerPos == 0) {
int length = Math.min(buffer.length, utfLenght - pos);
in.readFully(buffer, 0, length);
}
return buffer[innerPos];
}
public static boolean useOldStringConstructor() {
try {
Class clazz = String.class;
clazz.getDeclaredConstructor(int.class, int.class, char[].class);
return true;
} catch (Throwable ignore) {
}
return false;
}
private static UTFEncoderDecoder buildUTFUtil() {
try {
Class clazz = Class.forName("com.hazelcast.nio.utf8.EnterpriseStringCreator");
Method method = clazz.getDeclaredMethod("findBestStringCreator");
return new UTFEncoderDecoder((StringCreator) method.invoke(clazz), true);
} catch (Throwable t) {
}
boolean faststringEnabled = Boolean.parseBoolean(System.getProperty("hazelcast.nio.faststring", "true"));
return new UTFEncoderDecoder(faststringEnabled ? buildFastStringCreator() : new DefaultStringCreator(), false);
}
private static StringCreator buildFastStringCreator() {
try {
// Give access to the package private String constructor
Constructor constructor = null;
if (UTFEncoderDecoder.useOldStringConstructor()) {
constructor = String.class.getDeclaredConstructor(int.class, int.class, char[].class);
} else {
constructor = String.class.getDeclaredConstructor(char[].class, boolean.class);
}
if (constructor != null) {
constructor.setAccessible(true);
return new FastStringCreator(constructor);
}
} catch (Throwable ignore) {
}
return null;
}
private static class DefaultStringCreator implements UTFEncoderDecoder.StringCreator {
@Override
public String buildString(char[] chars) {
return new String(chars);
}
}
private static class FastStringCreator implements UTFEncoderDecoder.StringCreator {
private final Constructor constructor;
private final boolean useOldStringConstructor;
public FastStringCreator(Constructor constructor) {
this.constructor = constructor;
this.useOldStringConstructor = constructor.getParameterTypes().length == 3;
}
@Override
public String buildString(char[] chars) {
try {
if (useOldStringConstructor) {
return constructor.newInstance(0, chars.length, chars);
} else {
return constructor.newInstance(chars, Boolean.TRUE);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public interface StringCreator {
String buildString(char[] chars);
}
}