Suppress warnings in Kryo505ByteBufferInput
[controller.git] / atomix-storage / src / main / java / io / atomix / utils / serializer / Kryo505ByteBufferInput.java
1 /*
2  * Copyright (c) 2008, Nathan Sweet
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
6  * following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
9  *   disclaimer.
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.
14  *
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.
22  */
23 package io.atomix.utils.serializer;
24
25 import com.esotericsoftware.kryo.io.ByteBufferInput;
26 import java.nio.ByteBuffer;
27
28 /**
29  * A Kryo-4.0.3 ByteBufferInput adapted to deal with
30  * <a href="https://github.com/EsotericSoftware/kryo/issues/505">issue 505</a>.
31  *
32  * @author Roman Levenstein &lt;romixlev@gmail.com&gt;
33  * @author Robert Varga
34  */
35 @SuppressWarnings("all")
36 public final class Kryo505ByteBufferInput extends ByteBufferInput {
37         Kryo505ByteBufferInput (ByteBuffer buffer) {
38                 super(buffer);
39         }
40
41         @Override
42         public String readString () {
43                 niobuffer.position(position);
44                 int available = require(1);
45                 position++;
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);
50                 switch (charCount) {
51                 case 0:
52                         return null;
53                 case 1:
54                         return "";
55                 }
56                 charCount--;
57                 if (chars.length < charCount) chars = new char[charCount];
58                 readUtf8(charCount);
59                 return new String(chars, 0, charCount);
60         }
61
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.
65                         position++;
66                         b = niobuffer.get();
67                         result |= (b & 0x7F) << 6;
68                         if ((b & 0x80) != 0) {
69                                 position++;
70                                 b = niobuffer.get();
71                                 result |= (b & 0x7F) << 13;
72                                 if ((b & 0x80) != 0) {
73                                         position++;
74                                         b = niobuffer.get();
75                                         result |= (b & 0x7F) << 20;
76                                         if ((b & 0x80) != 0) {
77                                                 position++;
78                                                 b = niobuffer.get();
79                                                 result |= (b & 0x7F) << 27;
80                                         }
81                                 }
82                         }
83                 }
84                 return result;
85         }
86
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.
90                         require(1);
91                         position++;
92                         b = niobuffer.get();
93                         result |= (b & 0x7F) << 6;
94                         if ((b & 0x80) != 0) {
95                                 require(1);
96                                 position++;
97                                 b = niobuffer.get();
98                                 result |= (b & 0x7F) << 13;
99                                 if ((b & 0x80) != 0) {
100                                         require(1);
101                                         position++;
102                                         b = niobuffer.get();
103                                         result |= (b & 0x7F) << 20;
104                                         if ((b & 0x80) != 0) {
105                                                 require(1);
106                                                 position++;
107                                                 b = niobuffer.get();
108                                                 result |= (b & 0x7F) << 27;
109                                         }
110                                 }
111                         }
112                 }
113                 return result;
114         }
115
116         private void readUtf8 (int charCount) {
117                 char[] chars = this.chars;
118                 // Try to read 7 bit ASCII chars.
119                 int charIndex = 0;
120                 int count = Math.min(require(1), charCount);
121                 int position = this.position;
122                 int b;
123                 while (charIndex < count) {
124                         position++;
125                         b = niobuffer.get();
126                         if (b < 0) {
127                                 position--;
128                                 break;
129                         }
130                         chars[charIndex++] = (char)b;
131                 }
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);
137                 }
138         }
139
140         private void readUtf8_slow (int charCount, int charIndex) {
141                 char[] chars = this.chars;
142                 while (charIndex < charCount) {
143                         if (position == limit) require(1);
144                         position++;
145                         int b = niobuffer.get() & 0xFF;
146                         switch (b >> 4) {
147                         case 0:
148                         case 1:
149                         case 2:
150                         case 3:
151                         case 4:
152                         case 5:
153                         case 6:
154                         case 7:
155                                 chars[charIndex] = (char)b;
156                                 break;
157                         case 12:
158                         case 13:
159                                 if (position == limit) require(1);
160                                 position++;
161                                 chars[charIndex] = (char)((b & 0x1F) << 6 | niobuffer.get() & 0x3F);
162                                 break;
163                         case 14:
164                                 require(2);
165                                 position += 2;
166                                 int b2 = niobuffer.get();
167                                 int b3 = niobuffer.get();
168                                 chars[charIndex] = (char)((b & 0x0F) << 12 | (b2 & 0x3F) << 6 | b3 & 0x3F);
169                                 break;
170                         }
171                         charIndex++;
172                 }
173         }
174
175         private String readAscii () {
176                 int end = position;
177                 int start = end - 1;
178                 int limit = this.limit;
179                 int b;
180                 do {
181                         if (end == limit) return readAscii_slow();
182                         end++;
183                         b = niobuffer.get();
184                 } while ((b & 0x80) == 0);
185                 int count = end - start;
186                 byte[] tmp = new byte[count];
187                 niobuffer.position(start);
188                 niobuffer.get(tmp);
189                 tmp[count - 1] &= 0x7F;  // Mask end of ascii bit.
190                 String value = new String(tmp, 0, 0, count);
191                 position = end;
192                 niobuffer.position(position);
193                 return value;
194         }
195
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);
204                 position = limit;
205                 // Copy additional chars one by one.
206                 while (true) {
207                         require(1);
208                         position++;
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);
213                                 chars = newChars;
214                                 this.chars = newChars;
215                         }
216                         if ((b & 0x80) == 0x80) {
217                                 chars[charCount++] = (char)(b & 0x7F);
218                                 break;
219                         }
220                         chars[charCount++] = (char)b;
221                 }
222                 return new String(chars, 0, charCount);
223         }
224
225         @Override
226         public StringBuilder readStringBuilder () {
227                 niobuffer.position(position);
228                 int available = require(1);
229                 position++;
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);
234                 switch (charCount) {
235                 case 0:
236                         return null;
237                 case 1:
238                         return new StringBuilder("");
239                 }
240                 charCount--;
241                 if (chars.length < charCount) chars = new char[charCount];
242                 readUtf8(charCount);
243                 StringBuilder builder = new StringBuilder(charCount);
244                 builder.append(chars, 0, charCount);
245                 return builder;
246         }
247 }