comparison src/main/java/org/msgpack/unpacker/MessagePackUnpacker.java @ 0:cb825acd883a

first commit
author sugi
date Sat, 18 Oct 2014 15:06:15 +0900
parents
children 769ba8da0840
comparison
equal deleted inserted replaced
-1:000000000000 0:cb825acd883a
1 //
2 // MessagePack for Java
3 //
4 // Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 package org.msgpack.unpacker;
19
20 import java.io.IOException;
21 import java.io.EOFException;
22 import java.io.InputStream;
23 import java.math.BigInteger;
24 import org.msgpack.io.Input;
25 import org.msgpack.io.StreamInput;
26 import org.msgpack.io.BufferReferer;
27 import org.msgpack.MessagePack;
28 import org.msgpack.MessageTypeException;
29 import org.msgpack.packer.Unconverter;
30 import org.msgpack.type.ValueType;
31
32 public class MessagePackUnpacker extends AbstractUnpacker {
33 private static final byte REQUIRE_TO_READ_HEAD = (byte) 0xc1;
34
35 protected final Input in;
36 private final UnpackerStack stack = new UnpackerStack();
37
38 private byte headByte = REQUIRE_TO_READ_HEAD;
39
40 private byte[] raw;
41 private int rawFilled;
42
43 private final IntAccept intAccept = new IntAccept();
44 private final LongAccept longAccept = new LongAccept();
45 private final BigIntegerAccept bigIntegerAccept = new BigIntegerAccept();
46 private final DoubleAccept doubleAccept = new DoubleAccept();
47 private final ByteArrayAccept byteArrayAccept = new ByteArrayAccept();
48 private final StringAccept stringAccept = new StringAccept();
49 private final ArrayAccept arrayAccept = new ArrayAccept();
50 private final MapAccept mapAccept = new MapAccept();
51 private final ValueAccept valueAccept = new ValueAccept();
52 private final SkipAccept skipAccept = new SkipAccept();
53
54 public MessagePackUnpacker(MessagePack msgpack, InputStream stream) {
55 this(msgpack, new StreamInput(stream));
56 }
57
58 protected MessagePackUnpacker(MessagePack msgpack, Input in) {
59 super(msgpack);
60 this.in = in;
61 }
62
63 private byte getHeadByte() throws IOException {
64 byte b = headByte;
65 if (b == REQUIRE_TO_READ_HEAD) {
66 b = headByte = in.readByte();
67 }
68 return b;
69 }
70
71 final void readOne(Accept a) throws IOException {
72 stack.checkCount();
73 if (readOneWithoutStack(a)) {
74 stack.reduceCount();
75 }
76 }
77
78 final boolean readOneWithoutStack(Accept a) throws IOException {
79 if (raw != null) {
80 readRawBodyCont();
81 a.acceptRaw(raw);
82 raw = null;
83 headByte = REQUIRE_TO_READ_HEAD;
84 return true;
85 }
86
87 final int b = (int) getHeadByte();
88
89 if ((b & 0x80) == 0) { // Positive Fixnum
90 // System.out.println("positive fixnum "+b);
91 a.acceptInteger(b);
92 headByte = REQUIRE_TO_READ_HEAD;
93 return true;
94 }
95
96 if ((b & 0xe0) == 0xe0) { // Negative Fixnum
97 // System.out.println("negative fixnum "+b);
98 a.acceptInteger(b);
99 headByte = REQUIRE_TO_READ_HEAD;
100 return true;
101 }
102
103 if ((b & 0xe0) == 0xa0) { // FixRaw
104 int count = b & 0x1f;
105 if (count == 0) {
106 a.acceptEmptyRaw();
107 headByte = REQUIRE_TO_READ_HEAD;
108 return true;
109 }
110 if (!tryReferRawBody(a, count)) {
111 readRawBody(count);
112 a.acceptRaw(raw);
113 raw = null;
114 }
115 headByte = REQUIRE_TO_READ_HEAD;
116 return true;
117 }
118
119 if ((b & 0xf0) == 0x90) { // FixArray
120 int count = b & 0x0f;
121 // System.out.println("fixarray count:"+count);
122 a.acceptArray(count);
123 stack.reduceCount();
124 stack.pushArray(count);
125 headByte = REQUIRE_TO_READ_HEAD;
126 return false;
127 }
128
129 if ((b & 0xf0) == 0x80) { // FixMap
130 int count = b & 0x0f;
131 // System.out.println("fixmap count:"+count/2);
132 a.acceptMap(count);
133 stack.reduceCount();
134 stack.pushMap(count);
135 headByte = REQUIRE_TO_READ_HEAD;
136 return false;
137 }
138
139 return readOneWithoutStackLarge(a, b);
140 }
141
142 private boolean readOneWithoutStackLarge(Accept a, final int b)
143 throws IOException {
144 switch (b & 0xff) {
145 case 0xc0: // nil
146 a.acceptNil();
147 headByte = REQUIRE_TO_READ_HEAD;
148 return true;
149 case 0xc2: // false
150 a.acceptBoolean(false);
151 headByte = REQUIRE_TO_READ_HEAD;
152 return true;
153 case 0xc3: // true
154 a.acceptBoolean(true);
155 headByte = REQUIRE_TO_READ_HEAD;
156 return true;
157 //case 0xc4: // bin 8 -> see 0xd9
158 //case 0xc5: // bin 16 -> see 0xda
159 //case 0xc6: // bin 32 -> see 0xdb
160 case 0xca: // float
161 a.acceptFloat(in.getFloat());
162 in.advance();
163 headByte = REQUIRE_TO_READ_HEAD;
164 return true;
165 case 0xcb: // double
166 a.acceptDouble(in.getDouble());
167 in.advance();
168 headByte = REQUIRE_TO_READ_HEAD;
169 return true;
170 case 0xcc: // unsigned int 8
171 a.acceptUnsignedInteger(in.getByte());
172 in.advance();
173 headByte = REQUIRE_TO_READ_HEAD;
174 return true;
175 case 0xcd: // unsigned int 16
176 a.acceptUnsignedInteger(in.getShort());
177 in.advance();
178 headByte = REQUIRE_TO_READ_HEAD;
179 return true;
180 case 0xce: // unsigned int 32
181 a.acceptUnsignedInteger(in.getInt());
182 in.advance();
183 headByte = REQUIRE_TO_READ_HEAD;
184 return true;
185 case 0xcf: // unsigned int 64
186 a.acceptUnsignedInteger(in.getLong());
187 in.advance();
188 headByte = REQUIRE_TO_READ_HEAD;
189 return true;
190 case 0xd0: // signed int 8
191 a.acceptInteger(in.getByte());
192 in.advance();
193 headByte = REQUIRE_TO_READ_HEAD;
194 return true;
195 case 0xd1: // signed int 16
196 a.acceptInteger(in.getShort());
197 in.advance();
198 headByte = REQUIRE_TO_READ_HEAD;
199 return true;
200 case 0xd2: // signed int 32
201 a.acceptInteger(in.getInt());
202 in.advance();
203 headByte = REQUIRE_TO_READ_HEAD;
204 return true;
205 case 0xd3: // signed int 64
206 a.acceptInteger(in.getLong());
207 in.advance();
208 headByte = REQUIRE_TO_READ_HEAD;
209 return true;
210 case 0xc4: // bin 8
211 case 0xd9: // str 8
212 {
213 int count = in.getByte() & 0xff;
214 if (count == 0) {
215 a.acceptEmptyRaw();
216 in.advance();
217 headByte = REQUIRE_TO_READ_HEAD;
218 return true;
219 }
220 if (count >= rawSizeLimit) {
221 String reason = String.format(
222 "Size of raw (%d) over limit at %d",
223 new Object[] { count, rawSizeLimit });
224 throw new SizeLimitException(reason);
225 }
226 in.advance();
227 if (!tryReferRawBody(a, count)) {
228 readRawBody(count);
229 a.acceptRaw(raw);
230 raw = null;
231 }
232 headByte = REQUIRE_TO_READ_HEAD;
233 return true;
234 }
235 case 0xc5: // bin 16
236 case 0xda: // raw 16
237 {
238 int count = in.getShort() & 0xffff;
239 if (count == 0) {
240 a.acceptEmptyRaw();
241 in.advance();
242 headByte = REQUIRE_TO_READ_HEAD;
243 return true;
244 }
245 if (count >= rawSizeLimit) {
246 String reason = String.format(
247 "Size of raw (%d) over limit at %d",
248 new Object[] { count, rawSizeLimit });
249 throw new SizeLimitException(reason);
250 }
251 in.advance();
252 if (!tryReferRawBody(a, count)) {
253 readRawBody(count);
254 a.acceptRaw(raw);
255 raw = null;
256 }
257 headByte = REQUIRE_TO_READ_HEAD;
258 return true;
259 }
260 case 0xc6: // bin 32
261 case 0xdb: // raw 32
262 {
263 int count = in.getInt();
264 if (count == 0) {
265 a.acceptEmptyRaw();
266 in.advance();
267 headByte = REQUIRE_TO_READ_HEAD;
268 return true;
269 }
270 if (count < 0 || count >= rawSizeLimit) {
271 String reason = String.format(
272 "Size of raw (%d) over limit at %d",
273 new Object[] { count, rawSizeLimit });
274 throw new SizeLimitException(reason);
275 }
276 in.advance();
277 if (!tryReferRawBody(a, count)) {
278 readRawBody(count);
279 a.acceptRaw(raw);
280 raw = null;
281 }
282 headByte = REQUIRE_TO_READ_HEAD;
283 return true;
284 }
285 case 0xdc: // array 16
286 {
287 int count = in.getShort() & 0xffff;
288 if (count >= arraySizeLimit) {
289 String reason = String.format(
290 "Size of array (%d) over limit at %d",
291 new Object[] { count, arraySizeLimit });
292 throw new SizeLimitException(reason);
293 }
294 a.acceptArray(count);
295 stack.reduceCount();
296 stack.pushArray(count);
297 in.advance();
298 headByte = REQUIRE_TO_READ_HEAD;
299 return false;
300 }
301 case 0xdd: // array 32
302 {
303 int count = in.getInt();
304 if (count < 0 || count >= arraySizeLimit) {
305 String reason = String.format(
306 "Size of array (%d) over limit at %d",
307 new Object[] { count, arraySizeLimit });
308 throw new SizeLimitException(reason);
309 }
310 a.acceptArray(count);
311 stack.reduceCount();
312 stack.pushArray(count);
313 in.advance();
314 headByte = REQUIRE_TO_READ_HEAD;
315 return false;
316 }
317 case 0xde: // map 16
318 {
319 int count = in.getShort() & 0xffff;
320 if (count >= mapSizeLimit) {
321 String reason = String.format(
322 "Size of map (%d) over limit at %d",
323 new Object[] { count, mapSizeLimit });
324 throw new SizeLimitException(reason);
325 }
326 a.acceptMap(count);
327 stack.reduceCount();
328 stack.pushMap(count);
329 in.advance();
330 headByte = REQUIRE_TO_READ_HEAD;
331 return false;
332 }
333 case 0xdf: // map 32
334 {
335 int count = in.getInt();
336 if (count < 0 || count >= mapSizeLimit) {
337 String reason = String.format(
338 "Size of map (%d) over limit at %d",
339 new Object[] { count, mapSizeLimit });
340 throw new SizeLimitException(reason);
341 }
342 a.acceptMap(count);
343 stack.reduceCount();
344 stack.pushMap(count);
345 in.advance();
346 headByte = REQUIRE_TO_READ_HEAD;
347 return false;
348 }
349 default:
350 // System.out.println("unknown b "+(b&0xff));
351 // headByte = CS_INVALID
352 headByte = REQUIRE_TO_READ_HEAD;
353 throw new IOException("Invalid byte: " + b); // TODO error FormatException
354 }
355 }
356
357 private boolean tryReferRawBody(BufferReferer referer, int size) throws IOException {
358 return in.tryRefer(referer, size);
359 }
360
361 private void readRawBody(int size) throws IOException {
362 raw = new byte[size];
363 rawFilled = 0;
364 readRawBodyCont();
365 }
366
367 private void readRawBodyCont() throws IOException {
368 int len = in.read(raw, rawFilled, raw.length - rawFilled);
369 rawFilled += len;
370 if (rawFilled < raw.length) {
371 throw new EOFException();
372 }
373 }
374
375 @Override
376 protected boolean tryReadNil() throws IOException {
377 stack.checkCount();
378 int b = getHeadByte() & 0xff;
379 if (b == 0xc0) {
380 // nil is read
381 stack.reduceCount();
382 headByte = REQUIRE_TO_READ_HEAD;
383 return true;
384 }
385 // not nil
386 return false;
387 }
388
389 @Override
390 public boolean trySkipNil() throws IOException {
391 if (stack.getDepth() > 0 && stack.getTopCount() <= 0) {
392 // end of array or map
393 return true;
394 }
395
396 int b = getHeadByte() & 0xff;
397 if (b == 0xc0) {
398 // nil is skipped
399 stack.reduceCount();
400 headByte = REQUIRE_TO_READ_HEAD;
401 return true;
402 }
403 // not nil
404 return false;
405 }
406
407 @Override
408 public void readNil() throws IOException {
409 // optimized not to allocate nilAccept
410 stack.checkCount();
411 int b = getHeadByte() & 0xff;
412 if (b == 0xc0) {
413 stack.reduceCount();
414 headByte = REQUIRE_TO_READ_HEAD;
415 return;
416 }
417 throw new MessageTypeException("Expected nil but got not nil value");
418 }
419
420 @Override
421 public boolean readBoolean() throws IOException {
422 // optimized not to allocate booleanAccept
423 stack.checkCount();
424 int b = getHeadByte() & 0xff;
425 if (b == 0xc2) {
426 stack.reduceCount();
427 headByte = REQUIRE_TO_READ_HEAD;
428 return false;
429 } else if (b == 0xc3) {
430 stack.reduceCount();
431 headByte = REQUIRE_TO_READ_HEAD;
432 return true;
433 }
434 throw new MessageTypeException(
435 "Expected Boolean but got not boolean value");
436 }
437
438 @Override
439 public byte readByte() throws IOException {
440 // optimized not to allocate byteAccept
441 stack.checkCount();
442 readOneWithoutStack(intAccept);
443 int value = intAccept.value;
444 if (value < (int) Byte.MIN_VALUE || value > (int) Byte.MAX_VALUE) {
445 throw new MessageTypeException(); // TODO message
446 }
447 stack.reduceCount();
448 return (byte) value;
449 }
450
451 @Override
452 public short readShort() throws IOException {
453 // optimized not to allocate shortAccept
454 stack.checkCount();
455 readOneWithoutStack(intAccept);
456 int value = intAccept.value;
457 if (value < (int) Short.MIN_VALUE || value > (int) Short.MAX_VALUE) {
458 throw new MessageTypeException(); // TODO message
459 }
460 stack.reduceCount();
461 return (short) value;
462 }
463
464 @Override
465 public int readInt() throws IOException {
466 readOne(intAccept);
467 return intAccept.value;
468 }
469
470 @Override
471 public long readLong() throws IOException {
472 readOne(longAccept);
473 return longAccept.value;
474 }
475
476 @Override
477 public BigInteger readBigInteger() throws IOException {
478 readOne(bigIntegerAccept);
479 return bigIntegerAccept.value;
480 }
481
482 @Override
483 public float readFloat() throws IOException {
484 readOne(doubleAccept);
485 return (float) doubleAccept.value;
486 }
487
488 @Override
489 public double readDouble() throws IOException {
490 readOne(doubleAccept);
491 return doubleAccept.value;
492 }
493
494 @Override
495 public byte[] readByteArray() throws IOException {
496 readOne(byteArrayAccept);
497 return byteArrayAccept.value;
498 }
499
500 @Override
501 public String readString() throws IOException {
502 readOne(stringAccept);
503 return stringAccept.value;
504 }
505
506 @Override
507 public int readArrayBegin() throws IOException {
508 readOne(arrayAccept);
509 return arrayAccept.size;
510 }
511
512 @Override
513 public void readArrayEnd(boolean check) throws IOException {
514 if (!stack.topIsArray()) {
515 throw new MessageTypeException(
516 "readArrayEnd() is called but readArrayBegin() is not called");
517 }
518
519 int remain = stack.getTopCount();
520 if (remain > 0) {
521 if (check) {
522 throw new MessageTypeException(
523 "readArrayEnd(check=true) is called but the array is not end");
524 }
525 for (int i = 0; i < remain; i++) {
526 skip();
527 }
528 }
529 stack.pop();
530 }
531
532 @Override
533 public int readMapBegin() throws IOException {
534 readOne(mapAccept);
535 return mapAccept.size;
536 }
537
538 @Override
539 public void readMapEnd(boolean check) throws IOException {
540 if (!stack.topIsMap()) {
541 throw new MessageTypeException(
542 "readMapEnd() is called but readMapBegin() is not called");
543 }
544
545 int remain = stack.getTopCount();
546 if (remain > 0) {
547 if (check) {
548 throw new MessageTypeException(
549 "readMapEnd(check=true) is called but the map is not end");
550 }
551 for (int i = 0; i < remain; i++) {
552 skip();
553 }
554 }
555 stack.pop();
556 }
557
558 @Override
559 protected void readValue(Unconverter uc) throws IOException {
560 if (uc.getResult() != null) {
561 uc.resetResult();
562 }
563 valueAccept.setUnconverter(uc);
564
565 stack.checkCount();
566 if (readOneWithoutStack(valueAccept)) {
567 stack.reduceCount();
568 if (uc.getResult() != null) {
569 return;
570 }
571 }
572 while (true) {
573 while (stack.getTopCount() == 0) {
574 if (stack.topIsArray()) {
575 uc.writeArrayEnd(true);
576 stack.pop();
577 // stack.reduceCount();
578 } else if (stack.topIsMap()) {
579 uc.writeMapEnd(true);
580 stack.pop();
581 // stack.reduceCount();
582 } else {
583 throw new RuntimeException("invalid stack"); // FIXME error?
584 }
585 if (uc.getResult() != null) {
586 return;
587 }
588 }
589 readOne(valueAccept);
590 }
591 }
592
593 @Override
594 public void skip() throws IOException {
595 stack.checkCount();
596 if (readOneWithoutStack(skipAccept)) {
597 stack.reduceCount();
598 return;
599 }
600 int targetDepth = stack.getDepth() - 1;
601 while (true) {
602 while (stack.getTopCount() == 0) {
603 stack.pop();
604 if (stack.getDepth() <= targetDepth) {
605 return;
606 }
607 }
608 readOne(skipAccept);
609 }
610 }
611
612 public ValueType getNextType() throws IOException {
613 final int b = (int) getHeadByte();
614 if ((b & 0x80) == 0) { // Positive Fixnum
615 return ValueType.INTEGER;
616 }
617 if ((b & 0xe0) == 0xe0) { // Negative Fixnum
618 return ValueType.INTEGER;
619 }
620 if ((b & 0xe0) == 0xa0) { // FixRaw
621 return ValueType.RAW;
622 }
623 if ((b & 0xf0) == 0x90) { // FixArray
624 return ValueType.ARRAY;
625 }
626 if ((b & 0xf0) == 0x80) { // FixMap
627 return ValueType.MAP;
628 }
629 switch (b & 0xff) {
630 case 0xc0: // nil
631 return ValueType.NIL;
632 case 0xc2: // false
633 case 0xc3: // true
634 return ValueType.BOOLEAN;
635 case 0xca: // float
636 case 0xcb: // double
637 return ValueType.FLOAT;
638 case 0xcc: // unsigned int 8
639 case 0xcd: // unsigned int 16
640 case 0xce: // unsigned int 32
641 case 0xcf: // unsigned int 64
642 case 0xd0: // signed int 8
643 case 0xd1: // signed int 16
644 case 0xd2: // signed int 32
645 case 0xd3: // signed int 64
646 return ValueType.INTEGER;
647 // The definition based on a minor upgrade guide.
648 // https://github.com/msgpack/msgpack/blob/master/spec.md#impl-upgrade
649 case 0xc4: // bin 8
650 case 0xc5: // bin 16
651 case 0xc6: // bin 32
652 case 0xd9: // str8
653 case 0xda: // raw 16
654 case 0xdb: // raw 32
655 return ValueType.RAW;
656 case 0xdc: // array 16
657 case 0xdd: // array 32
658 return ValueType.ARRAY;
659 case 0xde: // map 16
660 case 0xdf: // map 32
661 return ValueType.MAP;
662 default:
663 throw new IOException("Invalid byte: " + b); // TODO error FormatException
664 }
665 }
666
667 public void reset() {
668 raw = null;
669 stack.clear();
670 }
671
672 public void close() throws IOException {
673 in.close();
674 }
675
676 @Override
677 public int getReadByteCount() {
678 return in.getReadByteCount();
679 }
680
681 @Override
682 public void resetReadByteCount() {
683 in.resetReadByteCount();
684 }
685 }