2 * Copyright (c) 2008, Nathan Sweet
5 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
6 * following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
10 * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided with the distribution.
12 * - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote product
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 package io.atomix.utils.serializer;
25 import com.esotericsoftware.kryo.io.ByteBufferInput;
26 import java.nio.ByteBuffer;
29 * A Kryo-4.0.3 ByteBufferInput adapted to deal with
30 * <a href="https://github.com/EsotericSoftware/kryo/issues/505">issue 505</a>.
32 * @author Roman Levenstein <romixlev@gmail.com>
33 * @author Robert Varga
35 @SuppressWarnings("all")
36 public final class Kryo505ByteBufferInput extends ByteBufferInput {
37 Kryo505ByteBufferInput (ByteBuffer buffer) {
42 public String readString () {
43 niobuffer.position(position);
44 int available = require(1);
46 int b = niobuffer.get();
47 if ((b & 0x80) == 0) return readAscii(); // ASCII.
48 // Null, empty, or UTF8.
49 int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
57 if (chars.length < charCount) chars = new char[charCount];
59 return new String(chars, 0, charCount);
62 private int readUtf8Length (int b) {
63 int result = b & 0x3F; // Mask all but first 6 bits.
64 if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
67 result |= (b & 0x7F) << 6;
68 if ((b & 0x80) != 0) {
71 result |= (b & 0x7F) << 13;
72 if ((b & 0x80) != 0) {
75 result |= (b & 0x7F) << 20;
76 if ((b & 0x80) != 0) {
79 result |= (b & 0x7F) << 27;
87 private int readUtf8Length_slow (int b) {
88 int result = b & 0x3F; // Mask all but first 6 bits.
89 if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
93 result |= (b & 0x7F) << 6;
94 if ((b & 0x80) != 0) {
98 result |= (b & 0x7F) << 13;
99 if ((b & 0x80) != 0) {
103 result |= (b & 0x7F) << 20;
104 if ((b & 0x80) != 0) {
108 result |= (b & 0x7F) << 27;
116 private void readUtf8 (int charCount) {
117 char[] chars = this.chars;
118 // Try to read 7 bit ASCII chars.
120 int count = Math.min(require(1), charCount);
121 int position = this.position;
123 while (charIndex < count) {
130 chars[charIndex++] = (char)b;
132 this.position = position;
133 // If buffer didn't hold all chars or any were not ASCII, use slow path for remainder.
134 if (charIndex < charCount) {
135 niobuffer.position(position);
136 readUtf8_slow(charCount, charIndex);
140 private void readUtf8_slow (int charCount, int charIndex) {
141 char[] chars = this.chars;
142 while (charIndex < charCount) {
143 if (position == limit) require(1);
145 int b = niobuffer.get() & 0xFF;
155 chars[charIndex] = (char)b;
159 if (position == limit) require(1);
161 chars[charIndex] = (char)((b & 0x1F) << 6 | niobuffer.get() & 0x3F);
166 int b2 = niobuffer.get();
167 int b3 = niobuffer.get();
168 chars[charIndex] = (char)((b & 0x0F) << 12 | (b2 & 0x3F) << 6 | b3 & 0x3F);
175 private String readAscii () {
178 int limit = this.limit;
181 if (end == limit) return readAscii_slow();
184 } while ((b & 0x80) == 0);
185 int count = end - start;
186 byte[] tmp = new byte[count];
187 niobuffer.position(start);
189 tmp[count - 1] &= 0x7F; // Mask end of ascii bit.
190 String value = new String(tmp, 0, 0, count);
192 niobuffer.position(position);
196 private String readAscii_slow () {
197 position--; // Re-read the first byte.
198 // Copy chars currently in buffer.
199 int charCount = limit - position;
200 if (charCount > chars.length) chars = new char[charCount * 2];
201 char[] chars = this.chars;
202 for (int i = position, ii = 0, n = limit; i < n; i++, ii++)
203 chars[ii] = (char)niobuffer.get(i);
205 // Copy additional chars one by one.
209 int b = niobuffer.get();
210 if (charCount == chars.length) {
211 char[] newChars = new char[charCount * 2];
212 System.arraycopy(chars, 0, newChars, 0, charCount);
214 this.chars = newChars;
216 if ((b & 0x80) == 0x80) {
217 chars[charCount++] = (char)(b & 0x7F);
220 chars[charCount++] = (char)b;
222 return new String(chars, 0, charCount);
226 public StringBuilder readStringBuilder () {
227 niobuffer.position(position);
228 int available = require(1);
230 int b = niobuffer.get();
231 if ((b & 0x80) == 0) return new StringBuilder(readAscii()); // ASCII.
232 // Null, empty, or UTF8.
233 int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
238 return new StringBuilder("");
241 if (chars.length < charCount) chars = new char[charCount];
243 StringBuilder builder = new StringBuilder(charCount);
244 builder.append(chars, 0, charCount);