• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wuwen5 / hessian / 17132572548

21 Aug 2025 04:02PM UTC coverage: 56.631% (+12.0%) from 44.593%
17132572548

push

github

web-flow
refactor: remove startData1\State1,move readArguments to HessianRpcInput (#26)

1519 of 2847 branches covered (53.35%)

Branch coverage included in aggregate %.

3494 of 6005 relevant lines covered (58.18%)

2.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.59
hessian2-codec/src/main/java/io/github/wuwen5/hessian/io/HessianDecoder.java
1
/*
2
 * Copyright (c) 2001-2008 Caucho Technology, Inc.  All rights reserved.
3
 *
4
 * The Apache Software License, Version 1.1
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 *
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in
15
 *    the documentation and/or other materials provided with the
16
 *    distribution.
17
 *
18
 * 3. The end-user documentation included with the redistribution, if
19
 *    any, must include the following acknowlegement:
20
 *       "This product includes software developed by the
21
 *        Caucho Technology (http://www.caucho.com/)."
22
 *    Alternately, this acknowlegement may appear in the software itself,
23
 *    if and wherever such third-party acknowlegements normally appear.
24
 *
25
 * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
26
 *    endorse or promote products derived from this software without prior
27
 *    written permission. For written permission, please contact
28
 *    info@caucho.com.
29
 *
30
 * 5. Products derived from this software may not be called "Resin"
31
 *    nor may "Resin" appear in their names without prior written
32
 *    permission of Caucho Technology.
33
 *
34
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
35
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37
 * DISCLAIMED.  IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
38
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
43
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
44
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
 *
46
 * @author Scott Ferguson
47
 */
48

49
package io.github.wuwen5.hessian.io;
50

51
import java.io.ByteArrayOutputStream;
52
import java.io.EOFException;
53
import java.io.IOException;
54
import java.io.InputStream;
55
import java.io.Reader;
56
import java.util.ArrayList;
57
import java.util.Date;
58
import lombok.Setter;
59
import lombok.extern.slf4j.Slf4j;
60

61
/**
62
 * Input stream for Hessian requests.
63
 *
64
 * <p>HessianInput is unbuffered, so any client needs to provide
65
 * its own buffering.
66
 *
67
 * <pre>
68
 * InputStream is = ...;
69
 * HessianInput in = new HessianInput(is);
70
 * in.readObject();
71
 *
72
 * </pre>
73
 */
74
@Slf4j
4✔
75
public class HessianDecoder extends AbstractHessianDecoder implements Hessian2Constants {
76

77
    private static final int END_OF_DATA = -2;
78

79
    private static final int SIZE = 1024;
80

81
    /**
82
     * standard, unmodified factory for deserializing objects
83
     */
84
    protected SerializerFactory defaultSerializerFactory;
85
    /**
86
     * factory for deserializing objects in the input stream
87
     * -- SETTER --
88
     * Sets the serializer factory.
89
     */
90
    @Setter
91
    protected SerializerFactory serializerFactory;
92

93
    private static boolean isCloseStreamOnClose;
94

95
    protected ArrayList<Object> refs = new ArrayList<>();
5✔
96
    protected ArrayList<ObjectDefinition> classDefs = new ArrayList<>();
5✔
97
    protected ArrayList<String> types = new ArrayList<>();
5✔
98

99
    /**
100
     * the underlying input stream
101
     */
102
    private InputStream is;
103

104
    private final byte[] buffer = new byte[SIZE];
4✔
105

106
    /**
107
     * a peek character
108
     */
109
    private int offset;
110

111
    private int length;
112

113
    private final StringBuilder sbuf = new StringBuilder();
5✔
114

115
    /**
116
     * true if this is the last chunk
117
     */
118
    private boolean isLastChunk;
119

120
    /**
121
     * the chunk length
122
     */
123
    private int chunkLength;
124

125
    private HessianDebugInputStream dIs;
126

127
    public HessianDecoder() {
2✔
128
        if (log.isTraceEnabled()) {
3!
129
            dIs = new HessianDebugInputStream(log::trace);
10✔
130
        }
131
    }
1✔
132

133
    /**
134
     * Creates a new Hessian input stream, initialized with an
135
     * underlying input stream.
136
     *
137
     * @param is the underlying input stream.
138
     */
139
    public HessianDecoder(InputStream is) {
140
        this();
2✔
141

142
        init(is);
3✔
143
    }
1✔
144

145
    /**
146
     * Gets the serializer factory.
147
     */
148
    public SerializerFactory getSerializerFactory() {
149
        // the default serializer factory cannot be modified by external
150
        // callers
151
        if (serializerFactory == defaultSerializerFactory) {
5!
152
            serializerFactory = new SerializerFactory();
5✔
153
        }
154

155
        return serializerFactory;
3✔
156
    }
157

158
    /**
159
     * Gets the serializer factory.
160
     */
161
    protected final SerializerFactory findSerializerFactory() {
162
        SerializerFactory factory = serializerFactory;
3✔
163

164
        if (factory == null) {
2✔
165
            factory = SerializerFactory.createDefault();
2✔
166
            defaultSerializerFactory = factory;
3✔
167
            serializerFactory = factory;
3✔
168
        }
169

170
        return factory;
2✔
171
    }
172

173
    public void allow(String pattern) {
174
        ClassFactory factory = getSerializerFactory().getClassFactory();
4✔
175

176
        factory.allow(pattern);
3✔
177
    }
1✔
178

179
    public static void setCloseStreamOnClose(boolean isClose) {
180
        isCloseStreamOnClose = isClose;
2✔
181
    }
1✔
182

183
    public static boolean isCloseStreamOnClose() {
184
        return isCloseStreamOnClose;
2✔
185
    }
186

187
    @Override
188
    public void init(InputStream is) {
189
        if (dIs != null) {
3!
190
            dIs.initPacket(is);
4✔
191
            is = dIs;
3✔
192
        }
193

194
        this.is = is;
3✔
195

196
        reset();
2✔
197
    }
1✔
198

199
    public void initPacket(InputStream is) {
200
        if (dIs != null) {
3!
201
            dIs.initPacket(is);
4✔
202
            is = dIs;
3✔
203
        }
204

205
        this.is = is;
3✔
206

207
        resetReferences();
2✔
208
    }
1✔
209

210
    /**
211
     * Reads a null
212
     *
213
     * <pre>
214
     * N
215
     * </pre>
216
     */
217
    @Override
218
    public void readNull() throws IOException {
219
        int tag = read();
3✔
220

221
        if (tag == BC_NULL) {
3✔
222
            return;
1✔
223
        }
224
        throw expect("null", tag);
5✔
225
    }
226

227
    /**
228
     * Reads a boolean
229
     *
230
     * <pre>
231
     * T
232
     * F
233
     * </pre>
234
     */
235
    @Override
236
    public boolean readBoolean() throws IOException {
237
        int tag = offset < length ? (buffer[offset++] & 0xff) : read();
21✔
238

239
        switch (tag) {
2!
240
            case BC_TRUE:
241
                return true;
2✔
242
            case BC_FALSE:
243
                return false;
2✔
244

245
                // direct integer
246
            case 0x80:
247
            case 0x81:
248
            case 0x82:
249
            case 0x83:
250
            case 0x84:
251
            case 0x85:
252
            case 0x86:
253
            case 0x87:
254
            case 0x88:
255
            case 0x89:
256
            case 0x8a:
257
            case 0x8b:
258
            case 0x8c:
259
            case 0x8d:
260
            case 0x8e:
261
            case 0x8f:
262

263
            case 0x90:
264
            case 0x91:
265
            case 0x92:
266
            case 0x93:
267
            case 0x94:
268
            case 0x95:
269
            case 0x96:
270
            case 0x97:
271
            case 0x98:
272
            case 0x99:
273
            case 0x9a:
274
            case 0x9b:
275
            case 0x9c:
276
            case 0x9d:
277
            case 0x9e:
278
            case 0x9f:
279

280
            case 0xa0:
281
            case 0xa1:
282
            case 0xa2:
283
            case 0xa3:
284
            case 0xa4:
285
            case 0xa5:
286
            case 0xa6:
287
            case 0xa7:
288
            case 0xa8:
289
            case 0xa9:
290
            case 0xaa:
291
            case 0xab:
292
            case 0xac:
293
            case 0xad:
294
            case 0xae:
295
            case 0xaf:
296

297
            case 0xb0:
298
            case 0xb1:
299
            case 0xb2:
300
            case 0xb3:
301
            case 0xb4:
302
            case 0xb5:
303
            case 0xb6:
304
            case 0xb7:
305
            case 0xb8:
306
            case 0xb9:
307
            case 0xba:
308
            case 0xbb:
309
            case 0xbc:
310
            case 0xbd:
311
            case 0xbe:
312
            case 0xbf:
313
                return tag != BC_INT_ZERO;
5!
314

315
                // INT_BYTE = 0
316
            case 0xc8:
317
                return read() != 0;
6!
318

319
                // INT_BYTE != 0
320
            case 0xc0:
321
            case 0xc1:
322
            case 0xc2:
323
            case 0xc3:
324
            case 0xc4:
325
            case 0xc5:
326
            case 0xc6:
327
            case 0xc7:
328
            case 0xc9:
329
            case 0xca:
330
            case 0xcb:
331
            case 0xcc:
332
            case 0xcd:
333
            case 0xce:
334
            case 0xcf:
335
                read();
3✔
336
                return true;
2✔
337

338
                // INT_SHORT = 0
339
            case BC_INT_SHORT_ZERO:
340
                return (256 * read() + read()) != 0;
11!
341

342
                // INT_SHORT != 0
343
            case 0xd0:
344
            case 0xd1:
345
            case 0xd2:
346
            case 0xd3:
347
            case 0xd5:
348
            case 0xd6:
349
            case 0xd7:
350
                read();
3✔
351
                read();
3✔
352
                return true;
2✔
353

354
            case 'I':
355
                return parseInt() != 0;
6!
356

357
            case 0xd8:
358
            case 0xd9:
359
            case 0xda:
360
            case 0xdb:
361
            case 0xdc:
362
            case 0xdd:
363
            case 0xde:
364
            case 0xdf:
365

366
            case 0xe0:
367
            case 0xe1:
368
            case 0xe2:
369
            case 0xe3:
370
            case 0xe4:
371
            case 0xe5:
372
            case 0xe6:
373
            case 0xe7:
374
            case 0xe8:
375
            case 0xe9:
376
            case 0xea:
377
            case 0xeb:
378
            case 0xec:
379
            case 0xed:
380
            case 0xee:
381
            case 0xef:
382
                return tag != BC_LONG_ZERO;
5!
383

384
                // LONG_BYTE = 0
385
            case BC_LONG_BYTE_ZERO:
386
                return read() != 0;
6!
387

388
                // LONG_BYTE != 0
389
            case 0xf0:
390
            case 0xf1:
391
            case 0xf2:
392
            case 0xf3:
393
            case 0xf4:
394
            case 0xf5:
395
            case 0xf6:
396
            case 0xf7:
397
            case 0xf9:
398
            case 0xfa:
399
            case 0xfb:
400
            case 0xfc:
401
            case 0xfd:
402
            case 0xfe:
403
            case 0xff:
404
                read();
3✔
405
                return true;
2✔
406

407
                // LONG_SHORT = 0
408
            case BC_LONG_SHORT_ZERO:
409
                return (256 * read() + read()) != 0;
×
410

411
                // LONG_SHORT != 0
412
            case 0x38:
413
            case 0x39:
414
            case 0x3a:
415
            case 0x3b:
416
            case 0x3d:
417
            case 0x3e:
418
            case 0x3f:
419
                read();
3✔
420
                read();
3✔
421
                return true;
2✔
422

423
            case BC_LONG_INT:
424
                return (0x1000000L * read() + 0x10000L * read() + 0x100 * read() + read()) != 0;
27!
425

426
            case BC_LONG:
427
                return parseLong() != 0;
8!
428

429
            case BC_DOUBLE_ZERO:
430
                return false;
2✔
431

432
            case BC_DOUBLE_ONE:
433
                return true;
2✔
434

435
            case BC_DOUBLE_BYTE:
436
                return read() != 0;
6!
437

438
            case BC_DOUBLE_SHORT:
439
                return (0x100 * read() + read()) != 0;
11!
440

441
            case BC_DOUBLE_MILL: {
442
                int mills = parseInt();
3✔
443

444
                return mills != 0;
5!
445
            }
446

447
            case BC_DOUBLE:
448
                return parseDouble() != 0.0;
8!
449

450
            case BC_NULL:
451
                return false;
2✔
452

453
            default:
454
                throw expect("boolean", tag);
5✔
455
        }
456
    }
457

458
    /**
459
     * Reads a short
460
     *
461
     * <pre>
462
     * I b32 b24 b16 b8
463
     * </pre>
464
     */
465
    public short readShort() throws IOException {
466
        return (short) readInt();
4✔
467
    }
468

469
    /**
470
     * Reads an integer
471
     *
472
     * <pre>
473
     * I b32 b24 b16 b8
474
     * </pre>
475
     */
476
    @Override
477
    public final int readInt() throws IOException {
478
        // int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
479
        int tag = read();
3✔
480

481
        switch (tag) {
2✔
482
            case BC_NULL:
483
                return 0;
2✔
484

485
            case BC_FALSE:
486
                return 0;
2✔
487

488
            case BC_TRUE:
489
                return 1;
2✔
490

491
                // direct integer
492
            case 0x80:
493
            case 0x81:
494
            case 0x82:
495
            case 0x83:
496
            case 0x84:
497
            case 0x85:
498
            case 0x86:
499
            case 0x87:
500
            case 0x88:
501
            case 0x89:
502
            case 0x8a:
503
            case 0x8b:
504
            case 0x8c:
505
            case 0x8d:
506
            case 0x8e:
507
            case 0x8f:
508

509
            case 0x90:
510
            case 0x91:
511
            case 0x92:
512
            case 0x93:
513
            case 0x94:
514
            case 0x95:
515
            case 0x96:
516
            case 0x97:
517
            case 0x98:
518
            case 0x99:
519
            case 0x9a:
520
            case 0x9b:
521
            case 0x9c:
522
            case 0x9d:
523
            case 0x9e:
524
            case 0x9f:
525

526
            case 0xa0:
527
            case 0xa1:
528
            case 0xa2:
529
            case 0xa3:
530
            case 0xa4:
531
            case 0xa5:
532
            case 0xa6:
533
            case 0xa7:
534
            case 0xa8:
535
            case 0xa9:
536
            case 0xaa:
537
            case 0xab:
538
            case 0xac:
539
            case 0xad:
540
            case 0xae:
541
            case 0xaf:
542

543
            case 0xb0:
544
            case 0xb1:
545
            case 0xb2:
546
            case 0xb3:
547
            case 0xb4:
548
            case 0xb5:
549
            case 0xb6:
550
            case 0xb7:
551
            case 0xb8:
552
            case 0xb9:
553
            case 0xba:
554
            case 0xbb:
555
            case 0xbc:
556
            case 0xbd:
557
            case 0xbe:
558
            case 0xbf:
559
                return tag - BC_INT_ZERO;
4✔
560

561
                /* byte int */
562
            case 0xc0:
563
            case 0xc1:
564
            case 0xc2:
565
            case 0xc3:
566
            case 0xc4:
567
            case 0xc5:
568
            case 0xc6:
569
            case 0xc7:
570
            case 0xc8:
571
            case 0xc9:
572
            case 0xca:
573
            case 0xcb:
574
            case 0xcc:
575
            case 0xcd:
576
            case 0xce:
577
            case 0xcf:
578
                return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
9✔
579

580
                /* short int */
581
            case 0xd0:
582
            case 0xd1:
583
            case 0xd2:
584
            case 0xd3:
585
            case 0xd4:
586
            case 0xd5:
587
            case 0xd6:
588
            case 0xd7:
589
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
14✔
590

591
            case 'I':
592
            case BC_LONG_INT:
593
                return ((read() << 24) + (read() << 16) + (read() << 8) + read());
18✔
594

595
                // direct long
596
            case 0xd8:
597
            case 0xd9:
598
            case 0xda:
599
            case 0xdb:
600
            case 0xdc:
601
            case 0xdd:
602
            case 0xde:
603
            case 0xdf:
604

605
            case 0xe0:
606
            case 0xe1:
607
            case 0xe2:
608
            case 0xe3:
609
            case 0xe4:
610
            case 0xe5:
611
            case 0xe6:
612
            case 0xe7:
613
            case 0xe8:
614
            case 0xe9:
615
            case 0xea:
616
            case 0xeb:
617
            case 0xec:
618
            case 0xed:
619
            case 0xee:
620
            case 0xef:
621
                return tag - BC_LONG_ZERO;
4✔
622

623
                /* byte long */
624
            case 0xf0:
625
            case 0xf1:
626
            case 0xf2:
627
            case 0xf3:
628
            case 0xf4:
629
            case 0xf5:
630
            case 0xf6:
631
            case 0xf7:
632
            case 0xf8:
633
            case 0xf9:
634
            case 0xfa:
635
            case 0xfb:
636
            case 0xfc:
637
            case 0xfd:
638
            case 0xfe:
639
            case 0xff:
640
                return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
9✔
641

642
                /* short long */
643
            case 0x38:
644
            case 0x39:
645
            case 0x3a:
646
            case 0x3b:
647
            case 0x3c:
648
            case 0x3d:
649
            case 0x3e:
650
            case 0x3f:
651
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
14✔
652

653
            case BC_LONG:
654
                return (int) parseLong();
4✔
655

656
            case BC_DOUBLE_ZERO:
657
                return 0;
2✔
658

659
            case BC_DOUBLE_ONE:
660
                return 1;
2✔
661

662
                // case LONG_BYTE:
663
            case BC_DOUBLE_BYTE:
664
                return (byte) (offset < length ? buffer[offset++] : read());
18!
665

666
                // case INT_SHORT:
667
                // case LONG_SHORT:
668
            case BC_DOUBLE_SHORT:
669
                return (short) (256 * read() + read());
9✔
670

671
            case BC_DOUBLE_MILL: {
672
                int mills = parseInt();
3✔
673

674
                return (int) (0.001 * mills);
6✔
675
            }
676

677
            case BC_DOUBLE:
678
                return (int) parseDouble();
4✔
679

680
            default:
681
                throw expect("integer", tag);
5✔
682
        }
683
    }
684

685
    /**
686
     * Reads a long
687
     *
688
     * <pre>
689
     * L b64 b56 b48 b40 b32 b24 b16 b8
690
     * </pre>
691
     */
692
    @Override
693
    public long readLong() throws IOException {
694
        int tag = read();
3✔
695

696
        switch (tag) {
2!
697
            case BC_NULL:
698
                return 0;
2✔
699

700
            case BC_FALSE:
701
                return 0;
2✔
702

703
            case BC_TRUE:
704
                return 1;
2✔
705

706
                // direct integer
707
            case 0x80:
708
            case 0x81:
709
            case 0x82:
710
            case 0x83:
711
            case 0x84:
712
            case 0x85:
713
            case 0x86:
714
            case 0x87:
715
            case 0x88:
716
            case 0x89:
717
            case 0x8a:
718
            case 0x8b:
719
            case 0x8c:
720
            case 0x8d:
721
            case 0x8e:
722
            case 0x8f:
723

724
            case 0x90:
725
            case 0x91:
726
            case 0x92:
727
            case 0x93:
728
            case 0x94:
729
            case 0x95:
730
            case 0x96:
731
            case 0x97:
732
            case 0x98:
733
            case 0x99:
734
            case 0x9a:
735
            case 0x9b:
736
            case 0x9c:
737
            case 0x9d:
738
            case 0x9e:
739
            case 0x9f:
740

741
            case 0xa0:
742
            case 0xa1:
743
            case 0xa2:
744
            case 0xa3:
745
            case 0xa4:
746
            case 0xa5:
747
            case 0xa6:
748
            case 0xa7:
749
            case 0xa8:
750
            case 0xa9:
751
            case 0xaa:
752
            case 0xab:
753
            case 0xac:
754
            case 0xad:
755
            case 0xae:
756
            case 0xaf:
757

758
            case 0xb0:
759
            case 0xb1:
760
            case 0xb2:
761
            case 0xb3:
762
            case 0xb4:
763
            case 0xb5:
764
            case 0xb6:
765
            case 0xb7:
766
            case 0xb8:
767
            case 0xb9:
768
            case 0xba:
769
            case 0xbb:
770
            case 0xbc:
771
            case 0xbd:
772
            case 0xbe:
773
            case 0xbf:
774
                return tag - BC_INT_ZERO;
5✔
775

776
                /* byte int */
777
            case 0xc0:
778
            case 0xc1:
779
            case 0xc2:
780
            case 0xc3:
781
            case 0xc4:
782
            case 0xc5:
783
            case 0xc6:
784
            case 0xc7:
785
            case 0xc8:
786
            case 0xc9:
787
            case 0xca:
788
            case 0xcb:
789
            case 0xcc:
790
            case 0xcd:
791
            case 0xce:
792
            case 0xcf:
793
                return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
10✔
794

795
                /* short int */
796
            case 0xd0:
797
            case 0xd1:
798
            case 0xd2:
799
            case 0xd3:
800
            case 0xd4:
801
            case 0xd5:
802
            case 0xd6:
803
            case 0xd7:
804
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
15✔
805

806
                // case LONG_BYTE:
807
            case BC_DOUBLE_BYTE:
808
                return (byte) (offset < length ? buffer[offset++] : read());
19!
809

810
                // case INT_SHORT:
811
                // case LONG_SHORT:
812
            case BC_DOUBLE_SHORT:
813
                return (short) (256 * read() + read());
10✔
814

815
            case BC_INT:
816
            case BC_LONG_INT:
817
                return parseInt();
4✔
818

819
                // direct long
820
            case 0xd8:
821
            case 0xd9:
822
            case 0xda:
823
            case 0xdb:
824
            case 0xdc:
825
            case 0xdd:
826
            case 0xde:
827
            case 0xdf:
828

829
            case 0xe0:
830
            case 0xe1:
831
            case 0xe2:
832
            case 0xe3:
833
            case 0xe4:
834
            case 0xe5:
835
            case 0xe6:
836
            case 0xe7:
837
            case 0xe8:
838
            case 0xe9:
839
            case 0xea:
840
            case 0xeb:
841
            case 0xec:
842
            case 0xed:
843
            case 0xee:
844
            case 0xef:
845
                return tag - BC_LONG_ZERO;
5✔
846

847
                /* byte long */
848
            case 0xf0:
849
            case 0xf1:
850
            case 0xf2:
851
            case 0xf3:
852
            case 0xf4:
853
            case 0xf5:
854
            case 0xf6:
855
            case 0xf7:
856
            case 0xf8:
857
            case 0xf9:
858
            case 0xfa:
859
            case 0xfb:
860
            case 0xfc:
861
            case 0xfd:
862
            case 0xfe:
863
            case 0xff:
864
                return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
×
865

866
                /* short long */
867
            case 0x38:
868
            case 0x39:
869
            case 0x3a:
870
            case 0x3b:
871
            case 0x3c:
872
            case 0x3d:
873
            case 0x3e:
874
            case 0x3f:
875
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
×
876

877
            case 'L':
878
                return parseLong();
3✔
879

880
            case BC_DOUBLE_ZERO:
881
                return 0;
2✔
882

883
            case BC_DOUBLE_ONE:
884
                return 1;
2✔
885

886
            case BC_DOUBLE_MILL: {
887
                int mills = parseInt();
3✔
888

889
                return (long) (0.001 * mills);
6✔
890
            }
891

892
            case BC_DOUBLE:
893
                return (long) parseDouble();
4✔
894

895
            default:
896
                throw expect("long", tag);
×
897
        }
898
    }
899

900
    /**
901
     * Reads a float
902
     *
903
     * <pre>
904
     * D b64 b56 b48 b40 b32 b24 b16 b8
905
     * </pre>
906
     */
907
    public float readFloat() throws IOException {
908
        return (float) readDouble();
4✔
909
    }
910

911
    /**
912
     * Reads a double
913
     *
914
     * <pre>
915
     * D b64 b56 b48 b40 b32 b24 b16 b8
916
     * </pre>
917
     */
918
    @Override
919
    public double readDouble() throws IOException {
920
        int tag = read();
3✔
921

922
        switch (tag) {
2!
923
            case BC_NULL:
924
            case BC_FALSE:
925
            case BC_DOUBLE_ZERO:
926
                return 0;
2✔
927

928
            case BC_TRUE:
929
                return 1;
2✔
930

931
                // direct integer
932
            case 0x80:
933
            case 0x81:
934
            case 0x82:
935
            case 0x83:
936
            case 0x84:
937
            case 0x85:
938
            case 0x86:
939
            case 0x87:
940
            case 0x88:
941
            case 0x89:
942
            case 0x8a:
943
            case 0x8b:
944
            case 0x8c:
945
            case 0x8d:
946
            case 0x8e:
947
            case 0x8f:
948

949
            case 0x90:
950
            case 0x91:
951
            case 0x92:
952
            case 0x93:
953
            case 0x94:
954
            case 0x95:
955
            case 0x96:
956
            case 0x97:
957
            case 0x98:
958
            case 0x99:
959
            case 0x9a:
960
            case 0x9b:
961
            case 0x9c:
962
            case 0x9d:
963
            case 0x9e:
964
            case 0x9f:
965

966
            case 0xa0:
967
            case 0xa1:
968
            case 0xa2:
969
            case 0xa3:
970
            case 0xa4:
971
            case 0xa5:
972
            case 0xa6:
973
            case 0xa7:
974
            case 0xa8:
975
            case 0xa9:
976
            case 0xaa:
977
            case 0xab:
978
            case 0xac:
979
            case 0xad:
980
            case 0xae:
981
            case 0xaf:
982

983
            case 0xb0:
984
            case 0xb1:
985
            case 0xb2:
986
            case 0xb3:
987
            case 0xb4:
988
            case 0xb5:
989
            case 0xb6:
990
            case 0xb7:
991
            case 0xb8:
992
            case 0xb9:
993
            case 0xba:
994
            case 0xbb:
995
            case 0xbc:
996
            case 0xbd:
997
            case 0xbe:
998
            case 0xbf:
999
                return tag - 0x90;
5✔
1000

1001
                /* byte int */
1002
            case 0xc0:
1003
            case 0xc1:
1004
            case 0xc2:
1005
            case 0xc3:
1006
            case 0xc4:
1007
            case 0xc5:
1008
            case 0xc6:
1009
            case 0xc7:
1010
            case 0xc8:
1011
            case 0xc9:
1012
            case 0xca:
1013
            case 0xcb:
1014
            case 0xcc:
1015
            case 0xcd:
1016
            case 0xce:
1017
            case 0xcf:
1018
                return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
10✔
1019

1020
                /* short int */
1021
            case 0xd0:
1022
            case 0xd1:
1023
            case 0xd2:
1024
            case 0xd3:
1025
            case 0xd4:
1026
            case 0xd5:
1027
            case 0xd6:
1028
            case 0xd7:
1029
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
15✔
1030

1031
            case BC_INT:
1032
            case BC_LONG_INT:
1033
                return parseInt();
4✔
1034

1035
                // direct long
1036
            case 0xd8:
1037
            case 0xd9:
1038
            case 0xda:
1039
            case 0xdb:
1040
            case 0xdc:
1041
            case 0xdd:
1042
            case 0xde:
1043
            case 0xdf:
1044

1045
            case 0xe0:
1046
            case 0xe1:
1047
            case 0xe2:
1048
            case 0xe3:
1049
            case 0xe4:
1050
            case 0xe5:
1051
            case 0xe6:
1052
            case 0xe7:
1053
            case 0xe8:
1054
            case 0xe9:
1055
            case 0xea:
1056
            case 0xeb:
1057
            case 0xec:
1058
            case 0xed:
1059
            case 0xee:
1060
            case 0xef:
1061
                return tag - BC_LONG_ZERO;
5✔
1062

1063
                /* byte long */
1064
            case 0xf0:
1065
            case 0xf1:
1066
            case 0xf2:
1067
            case 0xf3:
1068
            case 0xf4:
1069
            case 0xf5:
1070
            case 0xf6:
1071
            case 0xf7:
1072
            case 0xf8:
1073
            case 0xf9:
1074
            case 0xfa:
1075
            case 0xfb:
1076
            case 0xfc:
1077
            case 0xfd:
1078
            case 0xfe:
1079
            case 0xff:
1080
                return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
10✔
1081

1082
                /* short long */
1083
            case 0x38:
1084
            case 0x39:
1085
            case 0x3a:
1086
            case 0x3b:
1087
            case 0x3c:
1088
            case 0x3d:
1089
            case 0x3e:
1090
            case 0x3f:
1091
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
15✔
1092

1093
            case BC_LONG:
1094
                return (double) parseLong();
4✔
1095

1096
            case BC_DOUBLE_ONE:
1097
                return 1;
2✔
1098

1099
            case BC_DOUBLE_BYTE:
1100
                return (byte) (offset < length ? buffer[offset++] : read());
19!
1101

1102
            case BC_DOUBLE_SHORT:
1103
                return (short) (256 * read() + read());
10✔
1104

1105
            case BC_DOUBLE_MILL: {
1106
                int mills = parseInt();
3✔
1107

1108
                return 0.001 * mills;
5✔
1109
            }
1110

1111
            case BC_DOUBLE:
1112
                return parseDouble();
3✔
1113

1114
            default:
1115
                throw expect("double", tag);
×
1116
        }
1117
    }
1118

1119
    /**
1120
     * Reads a date.
1121
     *
1122
     * <pre>
1123
     * T b64 b56 b48 b40 b32 b24 b16 b8
1124
     * </pre>
1125
     */
1126
    @Override
1127
    public long readUTCDate() throws IOException {
1128
        int tag = read();
3✔
1129

1130
        if (tag == BC_DATE) {
3✔
1131
            return parseLong();
3✔
1132
        } else if (tag == BC_DATE_MINUTE) {
3!
1133
            return parseInt() * 60000L;
6✔
1134
        } else {
1135
            throw expect("date", tag);
×
1136
        }
1137
    }
1138

1139
    /**
1140
     * Reads a byte from the stream.
1141
     */
1142
    public int readChar() throws IOException {
1143
        if (chunkLength > 0) {
3✔
1144
            chunkLength--;
6✔
1145
            if (chunkLength == 0 && isLastChunk) {
6✔
1146
                chunkLength = END_OF_DATA;
3✔
1147
            }
1148

1149
            return parseUTF8Char();
3✔
1150
        } else if (chunkLength == END_OF_DATA) {
4✔
1151
            chunkLength = 0;
3✔
1152
            return -1;
2✔
1153
        }
1154

1155
        int tag = read();
3✔
1156

1157
        switch (tag) {
2!
1158
            case BC_NULL:
1159
                return -1;
×
1160

1161
            case BC_STRING:
1162
            case BC_STRING_CHUNK:
1163
                isLastChunk = tag == BC_STRING;
8✔
1164
                chunkLength = (read() << 8) + read();
9✔
1165

1166
                chunkLength--;
6✔
1167
                int value = parseUTF8Char();
3✔
1168

1169
                // special code so successive read byte won't
1170
                // be read as a single object.
1171
                if (chunkLength == 0 && isLastChunk) {
3!
1172
                    chunkLength = END_OF_DATA;
×
1173
                }
1174

1175
                return value;
2✔
1176

1177
            default:
1178
                throw expect("char", tag);
×
1179
        }
1180
    }
1181

1182
    /**
1183
     * Reads a byte array from the stream.
1184
     */
1185
    public int readString(char[] buffer, int offset, int length) throws IOException {
1186
        int readLength = 0;
2✔
1187

1188
        if (chunkLength == END_OF_DATA) {
4✔
1189
            chunkLength = 0;
3✔
1190
            return -1;
2✔
1191
        } else if (chunkLength == 0) {
3✔
1192
            int tag = read();
3✔
1193

1194
            switch (tag) {
2!
1195
                case BC_NULL:
1196
                    return -1;
×
1197

1198
                case BC_STRING:
1199
                case BC_STRING_CHUNK:
1200
                    isLastChunk = tag == BC_STRING;
8✔
1201
                    chunkLength = (read() << 8) + read();
9✔
1202
                    break;
1✔
1203

1204
                case 0x00:
1205
                case 0x01:
1206
                case 0x02:
1207
                case 0x03:
1208
                case 0x04:
1209
                case 0x05:
1210
                case 0x06:
1211
                case 0x07:
1212
                case 0x08:
1213
                case 0x09:
1214
                case 0x0a:
1215
                case 0x0b:
1216
                case 0x0c:
1217
                case 0x0d:
1218
                case 0x0e:
1219
                case 0x0f:
1220

1221
                case 0x10:
1222
                case 0x11:
1223
                case 0x12:
1224
                case 0x13:
1225
                case 0x14:
1226
                case 0x15:
1227
                case 0x16:
1228
                case 0x17:
1229
                case 0x18:
1230
                case 0x19:
1231
                case 0x1a:
1232
                case 0x1b:
1233
                case 0x1c:
1234
                case 0x1d:
1235
                case 0x1e:
1236
                case 0x1f:
1237
                    isLastChunk = true;
×
1238
                    chunkLength = tag - 0x00;
×
1239
                    break;
×
1240

1241
                case 0x30:
1242
                case 0x31:
1243
                case 0x32:
1244
                case 0x33:
1245
                    isLastChunk = true;
×
1246
                    chunkLength = (tag - 0x30) * 256 + read();
×
1247
                    break;
×
1248

1249
                default:
1250
                    throw expect("string", tag);
×
1251
            }
1252
        }
1253

1254
        while (length > 0) {
2✔
1255
            if (chunkLength > 0) {
3!
1256
                buffer[offset++] = (char) parseUTF8Char();
7✔
1257
                chunkLength--;
6✔
1258
                length--;
1✔
1259
                readLength++;
2✔
1260
            } else if (isLastChunk) {
×
1261
                if (readLength == 0) {
×
1262
                    return -1;
×
1263
                } else {
1264
                    chunkLength = END_OF_DATA;
×
1265
                    return readLength;
×
1266
                }
1267
            } else {
1268
                int tag = read();
×
1269

1270
                switch (tag) {
×
1271
                    case BC_STRING:
1272
                    case BC_STRING_CHUNK:
1273
                        isLastChunk = tag == BC_STRING;
×
1274
                        chunkLength = (read() << 8) + read();
×
1275
                        break;
×
1276

1277
                    case 0x00:
1278
                    case 0x01:
1279
                    case 0x02:
1280
                    case 0x03:
1281
                    case 0x04:
1282
                    case 0x05:
1283
                    case 0x06:
1284
                    case 0x07:
1285
                    case 0x08:
1286
                    case 0x09:
1287
                    case 0x0a:
1288
                    case 0x0b:
1289
                    case 0x0c:
1290
                    case 0x0d:
1291
                    case 0x0e:
1292
                    case 0x0f:
1293

1294
                    case 0x10:
1295
                    case 0x11:
1296
                    case 0x12:
1297
                    case 0x13:
1298
                    case 0x14:
1299
                    case 0x15:
1300
                    case 0x16:
1301
                    case 0x17:
1302
                    case 0x18:
1303
                    case 0x19:
1304
                    case 0x1a:
1305
                    case 0x1b:
1306
                    case 0x1c:
1307
                    case 0x1d:
1308
                    case 0x1e:
1309
                    case 0x1f:
1310
                        isLastChunk = true;
×
1311
                        chunkLength = tag - 0x00;
×
1312
                        break;
×
1313

1314
                    case 0x30:
1315
                    case 0x31:
1316
                    case 0x32:
1317
                    case 0x33:
1318
                        isLastChunk = true;
×
1319
                        chunkLength = (tag - 0x30) * 256 + read();
×
1320
                        break;
×
1321

1322
                    default:
1323
                        throw expect("string", tag);
×
1324
                }
1325
            }
×
1326
        }
1327

1328
        if (readLength == 0) {
2!
1329
            return -1;
×
1330
        } else if (chunkLength > 0 || !isLastChunk) {
6✔
1331
            return readLength;
2✔
1332
        } else {
1333
            chunkLength = END_OF_DATA;
3✔
1334
            return readLength;
2✔
1335
        }
1336
    }
1337

1338
    /**
1339
     * Reads a string
1340
     *
1341
     * <pre>
1342
     * S b16 b8 string value
1343
     * </pre>
1344
     */
1345
    @Override
1346
    public String readString() throws IOException {
1347
        int tag = read();
3✔
1348

1349
        switch (tag) {
2!
1350
            case BC_NULL:
1351
                return null;
2✔
1352
            case BC_TRUE:
1353
                return "true";
2✔
1354
            case BC_FALSE:
1355
                return "false";
2✔
1356

1357
                // direct integer
1358
            case 0x80:
1359
            case 0x81:
1360
            case 0x82:
1361
            case 0x83:
1362
            case 0x84:
1363
            case 0x85:
1364
            case 0x86:
1365
            case 0x87:
1366
            case 0x88:
1367
            case 0x89:
1368
            case 0x8a:
1369
            case 0x8b:
1370
            case 0x8c:
1371
            case 0x8d:
1372
            case 0x8e:
1373
            case 0x8f:
1374

1375
            case 0x90:
1376
            case 0x91:
1377
            case 0x92:
1378
            case 0x93:
1379
            case 0x94:
1380
            case 0x95:
1381
            case 0x96:
1382
            case 0x97:
1383
            case 0x98:
1384
            case 0x99:
1385
            case 0x9a:
1386
            case 0x9b:
1387
            case 0x9c:
1388
            case 0x9d:
1389
            case 0x9e:
1390
            case 0x9f:
1391

1392
            case 0xa0:
1393
            case 0xa1:
1394
            case 0xa2:
1395
            case 0xa3:
1396
            case 0xa4:
1397
            case 0xa5:
1398
            case 0xa6:
1399
            case 0xa7:
1400
            case 0xa8:
1401
            case 0xa9:
1402
            case 0xaa:
1403
            case 0xab:
1404
            case 0xac:
1405
            case 0xad:
1406
            case 0xae:
1407
            case 0xaf:
1408

1409
            case 0xb0:
1410
            case 0xb1:
1411
            case 0xb2:
1412
            case 0xb3:
1413
            case 0xb4:
1414
            case 0xb5:
1415
            case 0xb6:
1416
            case 0xb7:
1417
            case 0xb8:
1418
            case 0xb9:
1419
            case 0xba:
1420
            case 0xbb:
1421
            case 0xbc:
1422
            case 0xbd:
1423
            case 0xbe:
1424
            case 0xbf:
1425
                return String.valueOf((tag - 0x90));
5✔
1426

1427
                /* byte int */
1428
            case 0xc0:
1429
            case 0xc1:
1430
            case 0xc2:
1431
            case 0xc3:
1432
            case 0xc4:
1433
            case 0xc5:
1434
            case 0xc6:
1435
            case 0xc7:
1436
            case 0xc8:
1437
            case 0xc9:
1438
            case 0xca:
1439
            case 0xcb:
1440
            case 0xcc:
1441
            case 0xcd:
1442
            case 0xce:
1443
            case 0xcf:
1444
                return String.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read());
10✔
1445

1446
                /* short int */
1447
            case 0xd0:
1448
            case 0xd1:
1449
            case 0xd2:
1450
            case 0xd3:
1451
            case 0xd4:
1452
            case 0xd5:
1453
            case 0xd6:
1454
            case 0xd7:
1455
                return String.valueOf(((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read());
15✔
1456

1457
            case BC_INT:
1458
            case BC_LONG_INT:
1459
                return String.valueOf(parseInt());
4✔
1460

1461
                // direct long
1462
            case 0xd8:
1463
            case 0xd9:
1464
            case 0xda:
1465
            case 0xdb:
1466
            case 0xdc:
1467
            case 0xdd:
1468
            case 0xde:
1469
            case 0xdf:
1470

1471
            case 0xe0:
1472
            case 0xe1:
1473
            case 0xe2:
1474
            case 0xe3:
1475
            case 0xe4:
1476
            case 0xe5:
1477
            case 0xe6:
1478
            case 0xe7:
1479
            case 0xe8:
1480
            case 0xe9:
1481
            case 0xea:
1482
            case 0xeb:
1483
            case 0xec:
1484
            case 0xed:
1485
            case 0xee:
1486
            case 0xef:
1487
                return String.valueOf(tag - BC_LONG_ZERO);
5✔
1488

1489
                /* byte long */
1490
            case 0xf0:
1491
            case 0xf1:
1492
            case 0xf2:
1493
            case 0xf3:
1494
            case 0xf4:
1495
            case 0xf5:
1496
            case 0xf6:
1497
            case 0xf7:
1498
            case 0xf8:
1499
            case 0xf9:
1500
            case 0xfa:
1501
            case 0xfb:
1502
            case 0xfc:
1503
            case 0xfd:
1504
            case 0xfe:
1505
            case 0xff:
1506
                return String.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read());
10✔
1507

1508
                /* short long */
1509
            case 0x38:
1510
            case 0x39:
1511
            case 0x3a:
1512
            case 0x3b:
1513
            case 0x3c:
1514
            case 0x3d:
1515
            case 0x3e:
1516
            case 0x3f:
1517
                return String.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read());
15✔
1518

1519
            case BC_LONG:
1520
                return String.valueOf(parseLong());
4✔
1521

1522
            case BC_DOUBLE_ZERO:
1523
                return "0.0";
2✔
1524

1525
            case BC_DOUBLE_ONE:
1526
                return "1.0";
2✔
1527

1528
            case BC_DOUBLE_BYTE:
1529
                return String.valueOf((byte) (offset < length ? buffer[offset++] : read()));
19!
1530

1531
            case BC_DOUBLE_SHORT:
1532
                return String.valueOf(((short) (256 * read() + read())));
10✔
1533

1534
            case BC_DOUBLE_MILL: {
1535
                int mills = parseInt();
3✔
1536

1537
                return String.valueOf(0.001 * mills);
6✔
1538
            }
1539

1540
            case BC_DOUBLE:
1541
                return String.valueOf(parseDouble());
4✔
1542

1543
            case BC_STRING:
1544
            case BC_STRING_CHUNK:
1545
                isLastChunk = tag == BC_STRING;
7!
1546
                chunkLength = (read() << 8) + read();
9✔
1547

1548
                sbuf.setLength(0);
4✔
1549
                int ch;
1550

1551
                while ((ch = parseChar()) >= 0) {
5✔
1552
                    sbuf.append((char) ch);
7✔
1553
                }
1554

1555
                return sbuf.toString();
4✔
1556

1557
                // 0-byte string
1558
            case 0x00:
1559
            case 0x01:
1560
            case 0x02:
1561
            case 0x03:
1562
            case 0x04:
1563
            case 0x05:
1564
            case 0x06:
1565
            case 0x07:
1566
            case 0x08:
1567
            case 0x09:
1568
            case 0x0a:
1569
            case 0x0b:
1570
            case 0x0c:
1571
            case 0x0d:
1572
            case 0x0e:
1573
            case 0x0f:
1574

1575
            case 0x10:
1576
            case 0x11:
1577
            case 0x12:
1578
            case 0x13:
1579
            case 0x14:
1580
            case 0x15:
1581
            case 0x16:
1582
            case 0x17:
1583
            case 0x18:
1584
            case 0x19:
1585
            case 0x1a:
1586
            case 0x1b:
1587
            case 0x1c:
1588
            case 0x1d:
1589
            case 0x1e:
1590
            case 0x1f:
1591
                isLastChunk = true;
3✔
1592
                chunkLength = tag - 0x00;
5✔
1593

1594
                sbuf.setLength(0);
4✔
1595

1596
                while ((ch = parseChar()) >= 0) {
5✔
1597
                    sbuf.append((char) ch);
7✔
1598
                }
1599

1600
                return sbuf.toString();
4✔
1601

1602
            case 0x30:
1603
            case 0x31:
1604
            case 0x32:
1605
            case 0x33:
1606
                isLastChunk = true;
3✔
1607
                chunkLength = (tag - 0x30) * 256 + read();
10✔
1608

1609
                sbuf.setLength(0);
4✔
1610

1611
                while ((ch = parseChar()) >= 0) {
5✔
1612
                    sbuf.append((char) ch);
7✔
1613
                }
1614

1615
                return sbuf.toString();
4✔
1616

1617
            default:
1618
                throw expect("string", tag);
×
1619
        }
1620
    }
1621

1622
    /**
1623
     * Reads a byte array
1624
     *
1625
     * <pre>
1626
     * B b16 b8 data value
1627
     * </pre>
1628
     */
1629
    @Override
1630
    public byte[] readBytes() throws IOException {
1631
        int tag = read();
3✔
1632

1633
        switch (tag) {
2!
1634
            case BC_NULL:
1635
                return null;
2✔
1636

1637
            case BC_BINARY:
1638
            case BC_BINARY_CHUNK:
1639
                isLastChunk = tag == BC_BINARY;
7!
1640
                chunkLength = (read() << 8) + read();
9✔
1641

1642
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
4✔
1643

1644
                int data;
1645
                while ((data = parseByte()) >= 0) {
5✔
1646
                    bos.write(data);
4✔
1647
                }
1648

1649
                return bos.toByteArray();
3✔
1650

1651
            case 0x20:
1652
            case 0x21:
1653
            case 0x22:
1654
            case 0x23:
1655
            case 0x24:
1656
            case 0x25:
1657
            case 0x26:
1658
            case 0x27:
1659
            case 0x28:
1660
            case 0x29:
1661
            case 0x2a:
1662
            case 0x2b:
1663
            case 0x2c:
1664
            case 0x2d:
1665
            case 0x2e:
1666
            case 0x2f: {
1667
                isLastChunk = true;
3✔
1668
                chunkLength = tag - 0x20;
5✔
1669

1670
                byte[] bytes = new byte[chunkLength];
4✔
1671

1672
                int i = 0;
2✔
1673
                while (i < chunkLength) {
4✔
1674
                    int sublen = read(bytes, 0, chunkLength - i);
9✔
1675

1676
                    if (sublen <= 0) {
2!
1677
                        break;
×
1678
                    }
1679

1680
                    i += sublen;
4✔
1681
                }
1✔
1682

1683
                return bytes;
2✔
1684
            }
1685

1686
            case 0x34:
1687
            case 0x35:
1688
            case 0x36:
1689
            case 0x37: {
1690
                isLastChunk = true;
3✔
1691
                chunkLength = (tag - 0x34) * 256 + read();
10✔
1692

1693
                byte[] bytes = new byte[chunkLength];
4✔
1694

1695
                int i = 0;
2✔
1696
                while (i < chunkLength) {
4✔
1697
                    int sublen = read(bytes, 0, chunkLength - i);
9✔
1698

1699
                    if (sublen <= 0) {
2!
1700
                        break;
×
1701
                    }
1702

1703
                    i += sublen;
4✔
1704
                }
1✔
1705

1706
                return bytes;
2✔
1707
            }
1708

1709
            default:
1710
                throw expect("bytes", tag);
×
1711
        }
1712
    }
1713

1714
    /**
1715
     * Reads a byte from the stream.
1716
     */
1717
    public int readByte() throws IOException {
1718
        if (chunkLength > 0) {
3✔
1719
            chunkLength--;
6✔
1720
            if (chunkLength == 0 && isLastChunk) {
6!
1721
                chunkLength = END_OF_DATA;
×
1722
            }
1723

1724
            return read();
3✔
1725
        } else if (chunkLength == END_OF_DATA) {
4!
1726
            chunkLength = 0;
×
1727
            return -1;
×
1728
        }
1729

1730
        int tag = read();
3✔
1731

1732
        switch (tag) {
2!
1733
            case BC_NULL:
1734
                return -1;
×
1735

1736
            case BC_BINARY:
1737
            case BC_BINARY_CHUNK: {
1738
                isLastChunk = tag == BC_BINARY;
6!
1739
                chunkLength = (read() << 8) + read();
9✔
1740

1741
                int value = parseByte();
3✔
1742

1743
                // special code so successive read byte won't
1744
                // be read as a single object.
1745
                if (chunkLength == 0 && isLastChunk) {
3!
1746
                    chunkLength = END_OF_DATA;
×
1747
                }
1748

1749
                return value;
2✔
1750
            }
1751

1752
            case 0x20:
1753
            case 0x21:
1754
            case 0x22:
1755
            case 0x23:
1756
            case 0x24:
1757
            case 0x25:
1758
            case 0x26:
1759
            case 0x27:
1760
            case 0x28:
1761
            case 0x29:
1762
            case 0x2a:
1763
            case 0x2b:
1764
            case 0x2c:
1765
            case 0x2d:
1766
            case 0x2e:
1767
            case 0x2f: {
1768
                isLastChunk = true;
×
1769
                chunkLength = tag - 0x20;
×
1770

1771
                int value = parseByte();
×
1772

1773
                // special code so successive read byte won't
1774
                // be read as a single object.
1775
                if (chunkLength == 0) {
×
1776
                    chunkLength = END_OF_DATA;
×
1777
                }
1778

1779
                return value;
×
1780
            }
1781

1782
            case 0x34:
1783
            case 0x35:
1784
            case 0x36:
1785
            case 0x37: {
1786
                isLastChunk = true;
×
1787
                chunkLength = (tag - 0x34) * 256 + read();
×
1788

1789
                int value = parseByte();
×
1790

1791
                // special code so successive read byte won't
1792
                // be read as a single object.
1793
                if (chunkLength == 0) {
×
1794
                    chunkLength = END_OF_DATA;
×
1795
                }
1796

1797
                return value;
×
1798
            }
1799

1800
            default:
1801
                throw expect("binary", tag);
×
1802
        }
1803
    }
1804

1805
    /**
1806
     * Reads a byte array from the stream.
1807
     */
1808
    public int readBytes(byte[] buffer, int offset, int length) throws IOException {
1809
        int readLength = 0;
2✔
1810

1811
        if (chunkLength == END_OF_DATA) {
4!
1812
            chunkLength = 0;
×
1813
            return -1;
×
1814
        } else if (chunkLength == 0) {
3!
1815
            int tag = read();
3✔
1816

1817
            switch (tag) {
2!
1818
                case BC_NULL:
1819
                    return -1;
×
1820

1821
                case BC_BINARY:
1822
                case BC_BINARY_CHUNK:
1823
                    isLastChunk = tag == BC_BINARY;
6!
1824
                    chunkLength = (read() << 8) + read();
9✔
1825
                    break;
1✔
1826

1827
                case 0x20:
1828
                case 0x21:
1829
                case 0x22:
1830
                case 0x23:
1831
                case 0x24:
1832
                case 0x25:
1833
                case 0x26:
1834
                case 0x27:
1835
                case 0x28:
1836
                case 0x29:
1837
                case 0x2a:
1838
                case 0x2b:
1839
                case 0x2c:
1840
                case 0x2d:
1841
                case 0x2e:
1842
                case 0x2f: {
1843
                    isLastChunk = true;
×
1844
                    chunkLength = tag - 0x20;
×
1845
                    break;
×
1846
                }
1847

1848
                case 0x34:
1849
                case 0x35:
1850
                case 0x36:
1851
                case 0x37: {
1852
                    isLastChunk = true;
×
1853
                    chunkLength = (tag - 0x34) * 256 + read();
×
1854
                    break;
×
1855
                }
1856

1857
                default:
1858
                    throw expect("binary", tag);
×
1859
            }
1860
        }
1861

1862
        while (length > 0) {
2✔
1863
            if (chunkLength > 0) {
3✔
1864
                buffer[offset++] = (byte) read();
7✔
1865
                chunkLength--;
6✔
1866
                length--;
1✔
1867
                readLength++;
2✔
1868
            } else if (isLastChunk) {
3!
1869
                if (readLength == 0) return -1;
×
1870
                else {
1871
                    chunkLength = END_OF_DATA;
×
1872
                    return readLength;
×
1873
                }
1874
            } else {
1875
                int tag = read();
3✔
1876

1877
                switch (tag) {
2!
1878
                    case BC_BINARY:
1879
                    case BC_BINARY_CHUNK:
1880
                        isLastChunk = tag == BC_BINARY;
6!
1881
                        chunkLength = (read() << 8) + read();
9✔
1882
                        break;
1✔
1883

1884
                    default:
1885
                        throw expect("binary", tag);
×
1886
                }
1887
            }
1✔
1888
        }
1889

1890
        if (readLength == 0) {
2!
1891
            return -1;
×
1892
        } else if (chunkLength > 0 || !isLastChunk) {
3!
1893
            return readLength;
2✔
1894
        } else {
1895
            chunkLength = END_OF_DATA;
×
1896
            return readLength;
×
1897
        }
1898
    }
1899

1900
    /**
1901
     * Reads an object from the input stream with an expected type.
1902
     */
1903
    @Override
1904
    public Object readObject(Class cl) throws IOException {
1905
        if (cl == null || cl == Object.class) {
5!
1906
            return readObject();
3✔
1907
        }
1908

1909
        int tag = offset < length ? (buffer[offset++] & 0xff) : read();
21✔
1910

1911
        switch (tag) {
2!
1912
            case BC_NULL:
1913
                return null;
2✔
1914

1915
            case BC_MAP_UNTYPED: {
1916
                Deserializer reader = findSerializerFactory().getDeserializer(cl);
5✔
1917

1918
                return reader.readMap(this);
4✔
1919
            }
1920

1921
            case BC_MAP: {
1922
                String type = readType();
×
1923

1924
                // hessian/3bb3
1925
                if ("".equals(type)) {
×
1926
                    Deserializer reader;
1927
                    reader = findSerializerFactory().getDeserializer(cl);
×
1928

1929
                    return reader.readMap(this);
×
1930
                } else {
1931
                    Deserializer reader;
1932
                    reader = findSerializerFactory().getObjectDeserializer(type, cl);
×
1933

1934
                    return reader.readMap(this);
×
1935
                }
1936
            }
1937

1938
            case BC_OBJECT_DEF: {
1939
                readObjectDefinition();
2✔
1940

1941
                return readObject(cl);
4✔
1942
            }
1943

1944
            case 0x60:
1945
            case 0x61:
1946
            case 0x62:
1947
            case 0x63:
1948
            case 0x64:
1949
            case 0x65:
1950
            case 0x66:
1951
            case 0x67:
1952
            case 0x68:
1953
            case 0x69:
1954
            case 0x6a:
1955
            case 0x6b:
1956
            case 0x6c:
1957
            case 0x6d:
1958
            case 0x6e:
1959
            case 0x6f: {
1960
                int ref = tag - 0x60;
4✔
1961
                int size = classDefs.size();
4✔
1962

1963
                if (ref < 0 || size <= ref)
5!
1964
                    throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
×
1965

1966
                ObjectDefinition def = classDefs.get(ref);
6✔
1967

1968
                return readObjectInstance(cl, def);
5✔
1969
            }
1970

1971
            case BC_OBJECT: {
1972
                int ref = readInt();
×
1973
                int size = classDefs.size();
×
1974

1975
                if (ref < 0 || size <= ref)
×
1976
                    throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
×
1977

1978
                ObjectDefinition def = classDefs.get(ref);
×
1979

1980
                return readObjectInstance(cl, def);
×
1981
            }
1982

1983
            case BC_LIST_VARIABLE: {
1984
                String type = readType();
×
1985

1986
                Deserializer reader;
1987
                reader = findSerializerFactory().getListDeserializer(type, cl);
×
1988

1989
                return reader.readList(this, -1);
×
1990
            }
1991

1992
            case BC_LIST_FIXED: {
1993
                String type = readType();
3✔
1994
                int len = readInt();
3✔
1995

1996
                Deserializer reader;
1997
                reader = findSerializerFactory().getListDeserializer(type, cl);
6✔
1998

1999
                return reader.readLengthList(this, len);
5✔
2000
            }
2001

2002
            case 0x70:
2003
            case 0x71:
2004
            case 0x72:
2005
            case 0x73:
2006
            case 0x74:
2007
            case 0x75:
2008
            case 0x76:
2009
            case 0x77: {
2010
                int i = tag - 0x70;
4✔
2011

2012
                String type = readType();
3✔
2013

2014
                Deserializer reader;
2015
                reader = findSerializerFactory().getListDeserializer(type, cl);
6✔
2016

2017
                return reader.readLengthList(this, i);
5✔
2018
            }
2019

2020
            case BC_LIST_VARIABLE_UNTYPED: {
2021
                Deserializer reader;
2022
                reader = findSerializerFactory().getListDeserializer(null, cl);
×
2023

2024
                return reader.readList(this, -1);
×
2025
            }
2026

2027
            case BC_LIST_FIXED_UNTYPED: {
2028
                int len = readInt();
×
2029

2030
                Deserializer reader;
2031
                reader = findSerializerFactory().getListDeserializer(null, cl);
×
2032

2033
                return reader.readLengthList(this, len);
×
2034
            }
2035

2036
            case 0x78:
2037
            case 0x79:
2038
            case 0x7a:
2039
            case 0x7b:
2040
            case 0x7c:
2041
            case 0x7d:
2042
            case 0x7e:
2043
            case 0x7f: {
2044
                int i = tag - 0x78;
4✔
2045

2046
                Deserializer reader;
2047
                reader = findSerializerFactory().getListDeserializer(null, cl);
6✔
2048

2049
                return reader.readLengthList(this, i);
5✔
2050
            }
2051

2052
            case BC_REF: {
2053
                int ref = readInt();
3✔
2054

2055
                return refs.get(ref);
5✔
2056
            }
2057
        }
2058

2059
        if (tag >= 0) {
2!
2060
            offset--;
6✔
2061
        }
2062

2063
        return findSerializerFactory().getDeserializer(cl).readObject(this);
7✔
2064
    }
2065

2066
    /**
2067
     * Reads an arbitrary object from the input stream when the type
2068
     * is unknown.
2069
     */
2070
    @Override
2071
    public Object readObject() throws IOException {
2072
        int tag = offset < length ? (buffer[offset++] & 0xff) : read();
21✔
2073

2074
        switch (tag) {
2!
2075
            case BC_NULL:
2076
                return null;
2✔
2077

2078
            case BC_TRUE:
2079
                return Boolean.TRUE;
2✔
2080

2081
            case BC_FALSE:
2082
                return Boolean.FALSE;
2✔
2083

2084
                // direct integer
2085
            case 0x80:
2086
            case 0x81:
2087
            case 0x82:
2088
            case 0x83:
2089
            case 0x84:
2090
            case 0x85:
2091
            case 0x86:
2092
            case 0x87:
2093
            case 0x88:
2094
            case 0x89:
2095
            case 0x8a:
2096
            case 0x8b:
2097
            case 0x8c:
2098
            case 0x8d:
2099
            case 0x8e:
2100
            case 0x8f:
2101

2102
            case 0x90:
2103
            case 0x91:
2104
            case 0x92:
2105
            case 0x93:
2106
            case 0x94:
2107
            case 0x95:
2108
            case 0x96:
2109
            case 0x97:
2110
            case 0x98:
2111
            case 0x99:
2112
            case 0x9a:
2113
            case 0x9b:
2114
            case 0x9c:
2115
            case 0x9d:
2116
            case 0x9e:
2117
            case 0x9f:
2118

2119
            case 0xa0:
2120
            case 0xa1:
2121
            case 0xa2:
2122
            case 0xa3:
2123
            case 0xa4:
2124
            case 0xa5:
2125
            case 0xa6:
2126
            case 0xa7:
2127
            case 0xa8:
2128
            case 0xa9:
2129
            case 0xaa:
2130
            case 0xab:
2131
            case 0xac:
2132
            case 0xad:
2133
            case 0xae:
2134
            case 0xaf:
2135

2136
            case 0xb0:
2137
            case 0xb1:
2138
            case 0xb2:
2139
            case 0xb3:
2140
            case 0xb4:
2141
            case 0xb5:
2142
            case 0xb6:
2143
            case 0xb7:
2144
            case 0xb8:
2145
            case 0xb9:
2146
            case 0xba:
2147
            case 0xbb:
2148
            case 0xbc:
2149
            case 0xbd:
2150
            case 0xbe:
2151
            case 0xbf:
2152
                return tag - BC_INT_ZERO;
5✔
2153

2154
                /* byte int */
2155
            case 0xc0:
2156
            case 0xc1:
2157
            case 0xc2:
2158
            case 0xc3:
2159
            case 0xc4:
2160
            case 0xc5:
2161
            case 0xc6:
2162
            case 0xc7:
2163
            case 0xc8:
2164
            case 0xc9:
2165
            case 0xca:
2166
            case 0xcb:
2167
            case 0xcc:
2168
            case 0xcd:
2169
            case 0xce:
2170
            case 0xcf:
2171
                return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
10✔
2172

2173
                /* short int */
2174
            case 0xd0:
2175
            case 0xd1:
2176
            case 0xd2:
2177
            case 0xd3:
2178
            case 0xd4:
2179
            case 0xd5:
2180
            case 0xd6:
2181
            case 0xd7:
2182
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
15✔
2183

2184
            case BC_INT:
2185
                return parseInt();
4✔
2186

2187
                // direct long
2188
            case 0xd8:
2189
            case 0xd9:
2190
            case 0xda:
2191
            case 0xdb:
2192
            case 0xdc:
2193
            case 0xdd:
2194
            case 0xde:
2195
            case 0xdf:
2196

2197
            case 0xe0:
2198
            case 0xe1:
2199
            case 0xe2:
2200
            case 0xe3:
2201
            case 0xe4:
2202
            case 0xe5:
2203
            case 0xe6:
2204
            case 0xe7:
2205
            case 0xe8:
2206
            case 0xe9:
2207
            case 0xea:
2208
            case 0xeb:
2209
            case 0xec:
2210
            case 0xed:
2211
            case 0xee:
2212
            case 0xef:
2213
                return (long) (tag - BC_LONG_ZERO);
6✔
2214

2215
                /* byte long */
2216
            case 0xf0:
2217
            case 0xf1:
2218
            case 0xf2:
2219
            case 0xf3:
2220
            case 0xf4:
2221
            case 0xf5:
2222
            case 0xf6:
2223
            case 0xf7:
2224
            case 0xf8:
2225
            case 0xf9:
2226
            case 0xfa:
2227
            case 0xfb:
2228
            case 0xfc:
2229
            case 0xfd:
2230
            case 0xfe:
2231
            case 0xff:
2232
                return (long) (((tag - BC_LONG_BYTE_ZERO) << 8) + read());
11✔
2233

2234
                /* short long */
2235
            case 0x38:
2236
            case 0x39:
2237
            case 0x3a:
2238
            case 0x3b:
2239
            case 0x3c:
2240
            case 0x3d:
2241
            case 0x3e:
2242
            case 0x3f:
2243
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256L * read() + read();
18✔
2244

2245
            case BC_LONG_INT:
2246
                return (long) parseInt();
5✔
2247

2248
            case BC_LONG:
2249
                return parseLong();
4✔
2250

2251
            case BC_DOUBLE_ZERO:
2252
                return (double) 0;
3✔
2253

2254
            case BC_DOUBLE_ONE:
2255
                return 1.0;
3✔
2256

2257
            case BC_DOUBLE_BYTE:
2258
                return (double) (byte) read();
6✔
2259

2260
            case BC_DOUBLE_SHORT:
2261
                return (double) (short) (256 * read() + read());
11✔
2262

2263
            case BC_DOUBLE_MILL: {
2264
                int mills = parseInt();
3✔
2265

2266
                return 0.001 * mills;
6✔
2267
            }
2268

2269
            case BC_DOUBLE:
2270
                return parseDouble();
4✔
2271

2272
            case BC_DATE:
2273
                return new Date(parseLong());
6✔
2274

2275
            case BC_DATE_MINUTE:
2276
                return new Date(parseInt() * 60000L);
9✔
2277

2278
            case BC_STRING_CHUNK:
2279
            case BC_STRING: {
2280
                isLastChunk = tag == BC_STRING;
8✔
2281
                chunkLength = (read() << 8) + read();
9✔
2282

2283
                sbuf.setLength(0);
4✔
2284

2285
                parseString(sbuf);
4✔
2286

2287
                return sbuf.toString();
4✔
2288
            }
2289

2290
            case 0x00:
2291
            case 0x01:
2292
            case 0x02:
2293
            case 0x03:
2294
            case 0x04:
2295
            case 0x05:
2296
            case 0x06:
2297
            case 0x07:
2298
            case 0x08:
2299
            case 0x09:
2300
            case 0x0a:
2301
            case 0x0b:
2302
            case 0x0c:
2303
            case 0x0d:
2304
            case 0x0e:
2305
            case 0x0f:
2306

2307
            case 0x10:
2308
            case 0x11:
2309
            case 0x12:
2310
            case 0x13:
2311
            case 0x14:
2312
            case 0x15:
2313
            case 0x16:
2314
            case 0x17:
2315
            case 0x18:
2316
            case 0x19:
2317
            case 0x1a:
2318
            case 0x1b:
2319
            case 0x1c:
2320
            case 0x1d:
2321
            case 0x1e:
2322
            case 0x1f: {
2323
                isLastChunk = true;
3✔
2324
                chunkLength = tag;
3✔
2325

2326
                sbuf.setLength(0);
4✔
2327

2328
                parseString(sbuf);
4✔
2329

2330
                return sbuf.toString();
4✔
2331
            }
2332

2333
            case 0x30:
2334
            case 0x31:
2335
            case 0x32:
2336
            case 0x33: {
2337
                isLastChunk = true;
×
2338
                chunkLength = (tag - 0x30) * 256 + read();
×
2339

2340
                sbuf.setLength(0);
×
2341

2342
                parseString(sbuf);
×
2343

2344
                return sbuf.toString();
×
2345
            }
2346

2347
            case BC_BINARY_CHUNK:
2348
            case BC_BINARY: {
2349
                isLastChunk = tag == BC_BINARY;
×
2350
                chunkLength = (read() << 8) + read();
×
2351

2352
                int data;
2353
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
×
2354

2355
                while ((data = parseByte()) >= 0) {
×
2356
                    bos.write(data);
×
2357
                }
2358

2359
                return bos.toByteArray();
×
2360
            }
2361

2362
            case 0x20:
2363
            case 0x21:
2364
            case 0x22:
2365
            case 0x23:
2366
            case 0x24:
2367
            case 0x25:
2368
            case 0x26:
2369
            case 0x27:
2370
            case 0x28:
2371
            case 0x29:
2372
            case 0x2a:
2373
            case 0x2b:
2374
            case 0x2c:
2375
            case 0x2d:
2376
            case 0x2e:
2377
            case 0x2f: {
2378
                isLastChunk = true;
×
2379
                int len = tag - 0x20;
×
2380
                chunkLength = 0;
×
2381

2382
                byte[] data = new byte[len];
×
2383

2384
                for (int i = 0; i < len; i++) {
×
2385
                    data[i] = (byte) read();
×
2386
                }
2387

2388
                return data;
×
2389
            }
2390

2391
            case 0x34:
2392
            case 0x35:
2393
            case 0x36:
2394
            case 0x37: {
2395
                isLastChunk = true;
×
2396
                int len = (tag - 0x34) * 256 + read();
×
2397
                chunkLength = 0;
×
2398

2399
                byte[] bytes = new byte[len];
×
2400

2401
                for (int i = 0; i < len; i++) {
×
2402
                    bytes[i] = (byte) read();
×
2403
                }
2404

2405
                return bytes;
×
2406
            }
2407

2408
            case BC_LIST_VARIABLE: {
2409
                // variable length list
2410
                String type = readType();
3✔
2411

2412
                return findSerializerFactory().readList(this, -1, type);
7✔
2413
            }
2414

2415
            case BC_LIST_VARIABLE_UNTYPED: {
2416
                return findSerializerFactory().readList(this, -1, null);
7✔
2417
            }
2418

2419
            case BC_LIST_FIXED: {
2420
                // fixed length lists
2421
                String type = readType();
3✔
2422
                int len = readInt();
3✔
2423

2424
                Deserializer reader;
2425
                reader = findSerializerFactory().getListDeserializer(type, null);
6✔
2426

2427
                return reader.readLengthList(this, len);
5✔
2428
            }
2429

2430
            case BC_LIST_FIXED_UNTYPED: {
2431
                // fixed length lists
2432
                int len = readInt();
×
2433

2434
                Deserializer reader;
2435
                reader = findSerializerFactory().getListDeserializer(null, null);
×
2436

2437
                return reader.readLengthList(this, len);
×
2438
            }
2439

2440
                // compact fixed list
2441
            case 0x70:
2442
            case 0x71:
2443
            case 0x72:
2444
            case 0x73:
2445
            case 0x74:
2446
            case 0x75:
2447
            case 0x76:
2448
            case 0x77: {
2449
                // fixed length lists
2450
                String type = readType();
3✔
2451
                int len = tag - 0x70;
4✔
2452

2453
                Deserializer reader;
2454
                reader = findSerializerFactory().getListDeserializer(type, null);
6✔
2455

2456
                return reader.readLengthList(this, len);
5✔
2457
            }
2458

2459
                // compact fixed untyped list
2460
            case 0x78:
2461
            case 0x79:
2462
            case 0x7a:
2463
            case 0x7b:
2464
            case 0x7c:
2465
            case 0x7d:
2466
            case 0x7e:
2467
            case 0x7f: {
2468
                // fixed length lists
2469
                int len = tag - 0x78;
4✔
2470

2471
                Deserializer reader;
2472
                reader = findSerializerFactory().getListDeserializer(null, null);
6✔
2473

2474
                return reader.readLengthList(this, len);
5✔
2475
            }
2476

2477
            case BC_MAP_UNTYPED: {
2478
                return findSerializerFactory().readMap(this, null);
6✔
2479
            }
2480

2481
            case BC_MAP: {
2482
                String type = readType();
3✔
2483

2484
                return findSerializerFactory().readMap(this, type);
6✔
2485
            }
2486

2487
            case BC_OBJECT_DEF: {
2488
                readObjectDefinition();
2✔
2489

2490
                return readObject();
3✔
2491
            }
2492

2493
            case 0x60:
2494
            case 0x61:
2495
            case 0x62:
2496
            case 0x63:
2497
            case 0x64:
2498
            case 0x65:
2499
            case 0x66:
2500
            case 0x67:
2501
            case 0x68:
2502
            case 0x69:
2503
            case 0x6a:
2504
            case 0x6b:
2505
            case 0x6c:
2506
            case 0x6d:
2507
            case 0x6e:
2508
            case 0x6f: {
2509
                int ref = tag - 0x60;
4✔
2510

2511
                if (classDefs.size() <= ref)
5!
2512
                    throw error("No classes defined at reference '" + Integer.toHexString(tag) + "'");
×
2513

2514
                ObjectDefinition def = classDefs.get(ref);
6✔
2515

2516
                return readObjectInstance(null, def);
5✔
2517
            }
2518

2519
            case BC_OBJECT: {
2520
                int ref = readInt();
×
2521

2522
                if (classDefs.size() <= ref) {
×
2523
                    throw error("Illegal object reference #" + ref);
×
2524
                }
2525

2526
                ObjectDefinition def = classDefs.get(ref);
×
2527

2528
                return readObjectInstance(null, def);
×
2529
            }
2530

2531
            case BC_REF: {
2532
                int ref = readInt();
×
2533

2534
                return refs.get(ref);
×
2535
            }
2536

2537
            default:
2538
                if (tag < 0) {
2!
2539
                    throw new EOFException("readObject: unexpected end of file");
5✔
2540
                } else {
2541
                    throw error("readObject: unknown code " + codeName(tag));
×
2542
                }
2543
        }
2544
    }
2545

2546
    /**
2547
     * Reads an object definition:
2548
     *
2549
     * <pre>
2550
     * O string <int> (string)* <value>*
2551
     * </pre>
2552
     */
2553
    private void readObjectDefinition() throws IOException {
2554
        String type = readString();
3✔
2555
        int len = readInt();
3✔
2556

2557
        SerializerFactory factory = findSerializerFactory();
3✔
2558

2559
        Deserializer reader = factory.getObjectDeserializer(type, null);
5✔
2560

2561
        Object[] fields = reader.createFields(len);
4✔
2562
        String[] fieldNames = new String[len];
3✔
2563

2564
        for (int i = 0; i < len; i++) {
7✔
2565
            String name = readString();
3✔
2566

2567
            fields[i] = reader.createField(name);
6✔
2568
            fieldNames[i] = name;
4✔
2569
        }
2570

2571
        ObjectDefinition def = new ObjectDefinition(type, reader, fields, fieldNames);
8✔
2572

2573
        classDefs.add(def);
5✔
2574
    }
1✔
2575

2576
    private Object readObjectInstance(Class<?> cl, ObjectDefinition def) throws IOException {
2577
        String type = def.getType();
3✔
2578
        Deserializer reader = def.getReader();
3✔
2579
        Object[] fields = def.getFields();
3✔
2580

2581
        SerializerFactory factory = findSerializerFactory();
3✔
2582

2583
        if (cl != reader.getType() && cl != null) {
6✔
2584
            reader = factory.getObjectDeserializer(type, cl);
5✔
2585

2586
            return reader.readObject(this, def.getFieldNames());
6✔
2587
        } else {
2588
            return reader.readObject(this, fields);
5✔
2589
        }
2590
    }
2591

2592
    /**
2593
     * Reads a remote object.
2594
     */
2595
    @Override
2596
    public Object readRemote() throws IOException {
2597
        String type = readType();
×
2598
        String url = readString();
×
2599

2600
        return resolveRemote(type, url);
×
2601
    }
2602

2603
    /**
2604
     * Reads a reference.
2605
     */
2606
    @Override
2607
    public Object readRef() throws IOException {
2608
        int value = parseInt();
×
2609

2610
        return refs.get(value);
×
2611
    }
2612

2613
    /**
2614
     * Reads the start of a list.
2615
     */
2616
    @Override
2617
    public int readListStart() throws IOException {
2618
        return read();
×
2619
    }
2620

2621
    /**
2622
     * Reads the start of a list.
2623
     */
2624
    @Override
2625
    public int readMapStart() throws IOException {
2626
        return read();
×
2627
    }
2628

2629
    /**
2630
     * Returns true if this is the end of a list or a map.
2631
     */
2632
    @Override
2633
    public boolean isEnd() throws IOException {
2634
        int code;
2635

2636
        if (offset < length) {
5!
2637
            code = (buffer[offset] & 0xff);
9✔
2638
        } else {
2639
            code = read();
×
2640

2641
            if (code >= 0) {
×
2642
                offset--;
×
2643
            }
2644
        }
2645

2646
        return (code < 0 || code == 'Z');
9!
2647
    }
2648

2649
    /**
2650
     * Reads the end byte.
2651
     */
2652
    @Override
2653
    public void readEnd() throws IOException {
2654
        int code = offset < length ? (buffer[offset++] & 0xff) : read();
19!
2655

2656
        if (code != BC_END) {
3!
2657
            if (code < 0) {
×
2658
                throw error("unexpected end of file");
×
2659
            } else {
2660
                throw error("unknown code:" + codeName(code));
×
2661
            }
2662
        }
2663
    }
1✔
2664

2665
    /**
2666
     * Reads the end byte.
2667
     */
2668
    @Override
2669
    public void readMapEnd() throws IOException {
2670
        int code = offset < length ? (buffer[offset++] & 0xff) : read();
19!
2671

2672
        if (code != BC_END) {
3!
2673
            throw error("expected end of map ('Z') at '" + codeName(code) + "'");
×
2674
        }
2675
    }
1✔
2676

2677
    /**
2678
     * Reads the end byte.
2679
     */
2680
    @Override
2681
    public void readListEnd() throws IOException {
2682
        int code = offset < length ? (buffer[offset++] & 0xff) : read();
×
2683

2684
        if (code != BC_END) {
×
2685
            throw error("expected end of list ('Z') at '" + codeName(code) + "'");
×
2686
        }
2687
    }
×
2688

2689
    /**
2690
     * Adds a list/map reference.
2691
     */
2692
    @Override
2693
    public int addRef(Object ref) {
2694
        if (refs == null) {
3!
2695
            refs = new ArrayList<>();
×
2696
        }
2697

2698
        refs.add(ref);
5✔
2699

2700
        return refs.size() - 1;
6✔
2701
    }
2702

2703
    /**
2704
     * Adds a list/map reference.
2705
     */
2706
    @Override
2707
    public void setRef(int i, Object ref) {
2708
        refs.set(i, ref);
6✔
2709
    }
1✔
2710

2711
    /**
2712
     * Resets the references for streaming.
2713
     */
2714
    @Override
2715
    public void resetReferences() {
2716
        refs.clear();
3✔
2717
    }
1✔
2718

2719
    public void reset() {
2720
        resetReferences();
2✔
2721

2722
        classDefs.clear();
3✔
2723
        types.clear();
3✔
2724
    }
1✔
2725

2726
    public void resetBuffer() {
2727
        int i = this.offset;
×
2728
        this.offset = 0;
×
2729

2730
        int len = this.length;
×
2731
        this.length = 0;
×
2732

2733
        if (len > 0 && i != len) {
×
2734
            throw new IllegalStateException("offset=" + i + " length=" + len);
×
2735
        }
2736
    }
×
2737

2738
    public Object readStreamingObject() throws IOException {
2739
        if (refs != null) {
3!
2740
            refs.clear();
3✔
2741
        }
2742

2743
        return readObject();
3✔
2744
    }
2745

2746
    /**
2747
     * Resolves a remote object.
2748
     */
2749
    public Object resolveRemote(String type, String url) throws IOException {
2750
        HessianRemoteResolver resolver = getRemoteResolver();
×
2751

2752
        if (resolver != null) {
×
2753
            return resolver.lookup(type, url);
×
2754
        } else {
2755
            return new HessianRemote(type, url);
×
2756
        }
2757
    }
2758

2759
    /**
2760
     * Parses a type from the stream.
2761
     *
2762
     * <pre>
2763
     * type ::= string
2764
     * type ::= int
2765
     * </pre>
2766
     */
2767
    @Override
2768
    public String readType() throws IOException {
2769
        int code = offset < length ? (buffer[offset++] & 0xff) : read();
19!
2770
        offset--;
6✔
2771

2772
        switch (code) {
2✔
2773
            case 0x00:
2774
            case 0x01:
2775
            case 0x02:
2776
            case 0x03:
2777
            case 0x04:
2778
            case 0x05:
2779
            case 0x06:
2780
            case 0x07:
2781
            case 0x08:
2782
            case 0x09:
2783
            case 0x0a:
2784
            case 0x0b:
2785
            case 0x0c:
2786
            case 0x0d:
2787
            case 0x0e:
2788
            case 0x0f:
2789

2790
            case 0x10:
2791
            case 0x11:
2792
            case 0x12:
2793
            case 0x13:
2794
            case 0x14:
2795
            case 0x15:
2796
            case 0x16:
2797
            case 0x17:
2798
            case 0x18:
2799
            case 0x19:
2800
            case 0x1a:
2801
            case 0x1b:
2802
            case 0x1c:
2803
            case 0x1d:
2804
            case 0x1e:
2805
            case 0x1f:
2806

2807
            case 0x30:
2808
            case 0x31:
2809
            case 0x32:
2810
            case 0x33:
2811
            case BC_STRING_CHUNK:
2812
            case BC_STRING: {
2813
                String type = readString();
3✔
2814

2815
                if (types == null) {
3!
2816
                    types = new ArrayList<>();
×
2817
                }
2818

2819
                types.add(type);
5✔
2820

2821
                return type;
2✔
2822
            }
2823

2824
            default: {
2825
                int ref = readInt();
3✔
2826

2827
                if (types.size() <= ref) {
5!
2828
                    throw new IndexOutOfBoundsException(
×
2829
                            "type ref #" + ref + " is greater than the number of valid types (" + types.size() + ")");
×
2830
                }
2831

2832
                return types.get(ref);
6✔
2833
            }
2834
        }
2835
    }
2836

2837
    /**
2838
     * Parses the length for an array
2839
     *
2840
     * <pre>
2841
     * l b32 b24 b16 b8
2842
     * </pre>
2843
     */
2844
    @Override
2845
    public int readLength() {
2846
        throw new UnsupportedOperationException();
×
2847
    }
2848

2849
    /**
2850
     * Parses a 32-bit integer value from the stream.
2851
     *
2852
     * <pre>
2853
     * b32 b24 b16 b8
2854
     * </pre>
2855
     */
2856
    private int parseInt() throws IOException {
2857
        int i = this.offset;
3✔
2858

2859
        if (i + 3 < length) {
6!
2860
            byte[] buf = this.buffer;
3✔
2861

2862
            int b32 = buf[i] & 0xff;
6✔
2863
            int b24 = buf[i + 1] & 0xff;
8✔
2864
            int b16 = buf[i + 2] & 0xff;
8✔
2865
            int b8 = buf[i + 3] & 0xff;
8✔
2866

2867
            this.offset = i + 4;
5✔
2868

2869
            return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
14✔
2870
        } else {
2871
            int b32 = read();
×
2872
            int b24 = read();
×
2873
            int b16 = read();
×
2874
            int b8 = read();
×
2875

2876
            return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
×
2877
        }
2878
    }
2879

2880
    /**
2881
     * Parses a 64-bit long value from the stream.
2882
     *
2883
     * <pre>
2884
     * b64 b56 b48 b40 b32 b24 b16 b8
2885
     * </pre>
2886
     */
2887
    private long parseLong() throws IOException {
2888
        long b64 = read();
4✔
2889
        long b56 = read();
4✔
2890
        long b48 = read();
4✔
2891
        long b40 = read();
4✔
2892
        long b32 = read();
4✔
2893
        long b24 = read();
4✔
2894
        long b16 = read();
4✔
2895
        long b8 = read();
4✔
2896

2897
        return ((b64 << 56) + (b56 << 48) + (b48 << 40) + (b40 << 32) + (b32 << 24) + (b24 << 16) + (b16 << 8) + b8);
30✔
2898
    }
2899

2900
    /**
2901
     * Parses a 64-bit double value from the stream.
2902
     *
2903
     * <pre>
2904
     * b64 b56 b48 b40 b32 b24 b16 b8
2905
     * </pre>
2906
     */
2907
    private double parseDouble() throws IOException {
2908
        long bits = parseLong();
3✔
2909

2910
        return Double.longBitsToDouble(bits);
3✔
2911
    }
2912

2913
    private void parseString(StringBuilder sbuf) throws IOException {
2914
        while (true) {
2915
            if (chunkLength <= 0 && !parseChunkLength()) {
6✔
2916
                return;
1✔
2917
            }
2918

2919
            int i = chunkLength;
3✔
2920
            chunkLength = 0;
3✔
2921

2922
            while (i-- > 0) {
3✔
2923
                sbuf.append((char) parseUTF8Char());
7✔
2924
            }
2925
        }
1✔
2926
    }
2927

2928
    /**
2929
     * Reads a character from the underlying stream.
2930
     */
2931
    private int parseChar() throws IOException {
2932
        while (chunkLength <= 0) {
3✔
2933
            if (!parseChunkLength()) {
3!
2934
                return -1;
2✔
2935
            }
2936
        }
2937

2938
        chunkLength--;
6✔
2939

2940
        return parseUTF8Char();
3✔
2941
    }
2942

2943
    private boolean parseChunkLength() throws IOException {
2944
        if (isLastChunk) {
3✔
2945
            return false;
2✔
2946
        }
2947

2948
        int code = offset < length ? (buffer[offset++] & 0xff) : read();
19!
2949

2950
        switch (code) {
2!
2951
            case BC_STRING_CHUNK:
2952
                isLastChunk = false;
×
2953

2954
                chunkLength = (read() << 8) + read();
×
2955
                break;
×
2956

2957
            case BC_STRING:
2958
                isLastChunk = true;
3✔
2959

2960
                chunkLength = (read() << 8) + read();
9✔
2961
                break;
1✔
2962

2963
            case 0x00:
2964
            case 0x01:
2965
            case 0x02:
2966
            case 0x03:
2967
            case 0x04:
2968
            case 0x05:
2969
            case 0x06:
2970
            case 0x07:
2971
            case 0x08:
2972
            case 0x09:
2973
            case 0x0a:
2974
            case 0x0b:
2975
            case 0x0c:
2976
            case 0x0d:
2977
            case 0x0e:
2978
            case 0x0f:
2979

2980
            case 0x10:
2981
            case 0x11:
2982
            case 0x12:
2983
            case 0x13:
2984
            case 0x14:
2985
            case 0x15:
2986
            case 0x16:
2987
            case 0x17:
2988
            case 0x18:
2989
            case 0x19:
2990
            case 0x1a:
2991
            case 0x1b:
2992
            case 0x1c:
2993
            case 0x1d:
2994
            case 0x1e:
2995
            case 0x1f:
2996
                isLastChunk = true;
×
2997
                chunkLength = code - 0x00;
×
2998
                break;
×
2999

3000
            case 0x30:
3001
            case 0x31:
3002
            case 0x32:
3003
            case 0x33:
3004
                isLastChunk = true;
×
3005
                chunkLength = (code - 0x30) * 256 + read();
×
3006
                break;
×
3007

3008
            default:
3009
                throw expect("string", code);
×
3010
        }
3011

3012
        return true;
2✔
3013
    }
3014

3015
    /**
3016
     * Parses a single UTF8 character.
3017
     */
3018
    private int parseUTF8Char() throws IOException {
3019
        int ch = offset < length ? (buffer[offset++] & 0xff) : read();
21✔
3020

3021
        if (ch < 0x80) {
3✔
3022
            return ch;
2✔
3023
        } else if ((ch & 0xe0) == 0xc0) {
5!
3024
            int ch1 = read();
×
3025

3026
            return ((ch & 0x1f) << 6) + (ch1 & 0x3f);
×
3027
        } else if ((ch & 0xf0) == 0xe0) {
5!
3028
            int ch1 = read();
3✔
3029
            int ch2 = read();
3✔
3030

3031
            return ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
16✔
3032
        } else {
3033
            throw error("bad utf-8 encoding at " + codeName(ch));
×
3034
        }
3035
    }
3036

3037
    /**
3038
     * Reads a byte from the underlying stream.
3039
     */
3040
    private int parseByte() throws IOException {
3041
        while (chunkLength <= 0) {
3✔
3042
            if (isLastChunk) {
3!
3043
                return -1;
2✔
3044
            }
3045

3046
            int code = read();
×
3047

3048
            switch (code) {
×
3049
                case BC_BINARY_CHUNK:
3050
                    isLastChunk = false;
×
3051

3052
                    chunkLength = (read() << 8) + read();
×
3053
                    break;
×
3054

3055
                case BC_BINARY:
3056
                    isLastChunk = true;
×
3057

3058
                    chunkLength = (read() << 8) + read();
×
3059
                    break;
×
3060

3061
                case 0x20:
3062
                case 0x21:
3063
                case 0x22:
3064
                case 0x23:
3065
                case 0x24:
3066
                case 0x25:
3067
                case 0x26:
3068
                case 0x27:
3069
                case 0x28:
3070
                case 0x29:
3071
                case 0x2a:
3072
                case 0x2b:
3073
                case 0x2c:
3074
                case 0x2d:
3075
                case 0x2e:
3076
                case 0x2f:
3077
                    isLastChunk = true;
×
3078

3079
                    chunkLength = code - 0x20;
×
3080
                    break;
×
3081

3082
                case 0x34:
3083
                case 0x35:
3084
                case 0x36:
3085
                case 0x37:
3086
                    isLastChunk = true;
×
3087
                    chunkLength = (code - 0x34) * 256 + read();
×
3088
                    break;
×
3089

3090
                default:
3091
                    throw expect("byte[]", code);
×
3092
            }
3093
        }
×
3094

3095
        chunkLength--;
6✔
3096

3097
        return read();
3✔
3098
    }
3099

3100
    /**
3101
     * Reads bytes based on an input stream.
3102
     */
3103
    @Override
3104
    public InputStream readInputStream() throws IOException {
3105
        int tag = read();
3✔
3106

3107
        switch (tag) {
2!
3108
            case BC_NULL:
3109
                return null;
×
3110

3111
            case BC_BINARY:
3112
            case BC_BINARY_CHUNK:
3113
                isLastChunk = tag == BC_BINARY;
×
3114
                chunkLength = (read() << 8) + read();
×
3115
                break;
×
3116

3117
            case 0x20:
3118
            case 0x21:
3119
            case 0x22:
3120
            case 0x23:
3121
            case 0x24:
3122
            case 0x25:
3123
            case 0x26:
3124
            case 0x27:
3125
            case 0x28:
3126
            case 0x29:
3127
            case 0x2a:
3128
            case 0x2b:
3129
            case 0x2c:
3130
            case 0x2d:
3131
            case 0x2e:
3132
            case 0x2f:
3133
                isLastChunk = true;
3✔
3134
                chunkLength = tag - 0x20;
5✔
3135
                break;
1✔
3136

3137
            case 0x34:
3138
            case 0x35:
3139
            case 0x36:
3140
            case 0x37:
3141
                isLastChunk = true;
×
3142
                chunkLength = (tag - 0x34) * 256 + read();
×
3143
                break;
×
3144

3145
            default:
3146
                throw expect("binary", tag);
×
3147
        }
3148

3149
        return new ReadInputStream();
5✔
3150
    }
3151

3152
    /**
3153
     * Reads bytes from the underlying stream.
3154
     */
3155
    int read(byte[] buffer, int offset, int length) throws IOException {
3156
        int readLength = 0;
2✔
3157

3158
        while (length > 0) {
2✔
3159
            while (chunkLength <= 0) {
3✔
3160
                if (isLastChunk) {
3!
3161
                    return readLength == 0 ? -1 : readLength;
6✔
3162
                }
3163

3164
                int code = read();
×
3165

3166
                switch (code) {
×
3167
                    case BC_BINARY_CHUNK:
3168
                        isLastChunk = false;
×
3169

3170
                        chunkLength = (read() << 8) + read();
×
3171
                        break;
×
3172

3173
                    case BC_BINARY:
3174
                        isLastChunk = true;
×
3175

3176
                        chunkLength = (read() << 8) + read();
×
3177
                        break;
×
3178

3179
                    case 0x20:
3180
                    case 0x21:
3181
                    case 0x22:
3182
                    case 0x23:
3183
                    case 0x24:
3184
                    case 0x25:
3185
                    case 0x26:
3186
                    case 0x27:
3187
                    case 0x28:
3188
                    case 0x29:
3189
                    case 0x2a:
3190
                    case 0x2b:
3191
                    case 0x2c:
3192
                    case 0x2d:
3193
                    case 0x2e:
3194
                    case 0x2f:
3195
                        isLastChunk = true;
×
3196
                        chunkLength = code - 0x20;
×
3197
                        break;
×
3198

3199
                    case 0x34:
3200
                    case 0x35:
3201
                    case 0x36:
3202
                    case 0x37:
3203
                        isLastChunk = true;
×
3204
                        chunkLength = (code - 0x34) * 256 + read();
×
3205
                        break;
×
3206

3207
                    default:
3208
                        throw expect("byte[]", code);
×
3209
                }
3210
            }
×
3211

3212
            int sublen = chunkLength;
3✔
3213
            if (length < sublen) {
3!
3214
                sublen = length;
×
3215
            }
3216

3217
            if (this.length <= this.offset && !readBuffer()) {
5!
3218
                return -1;
×
3219
            }
3220

3221
            if (this.length - this.offset < sublen) {
7!
3222
                sublen = this.length - this.offset;
×
3223
            }
3224

3225
            System.arraycopy(this.buffer, this.offset, buffer, offset, sublen);
8✔
3226

3227
            this.offset += sublen;
6✔
3228

3229
            offset += sublen;
4✔
3230
            readLength += sublen;
4✔
3231
            length -= sublen;
4✔
3232
            chunkLength -= sublen;
6✔
3233
        }
1✔
3234

3235
        return readLength;
2✔
3236
    }
3237

3238
    /**
3239
     * Normally, shouldn't be called externally, but needed for QA, e.g.
3240
     * ejb/3b01.
3241
     */
3242
    public final int read() throws IOException {
3243
        if (length <= offset && !readBuffer()) {
8✔
3244
            return -1;
2✔
3245
        }
3246

3247
        return buffer[offset++] & 0xff;
13✔
3248
    }
3249

3250
    protected void unread() {
3251
        if (offset <= 0) {
×
3252
            throw new IllegalStateException();
×
3253
        }
3254

3255
        offset--;
×
3256
    }
×
3257

3258
    private boolean readBuffer() throws IOException {
3259
        byte[] bytes = this.buffer;
3✔
3260
        int i = this.offset;
3✔
3261

3262
        if (i < length) {
4!
3263
            System.arraycopy(bytes, i, bytes, 0, length - i);
×
3264
            i = length - i;
×
3265
        } else {
3266
            i = 0;
2✔
3267
        }
3268

3269
        int len = is.read(bytes, i, SIZE - i);
9✔
3270

3271
        if (len <= 0) {
2✔
3272
            this.length = i;
3✔
3273
            this.offset = 0;
3✔
3274

3275
            return i > 0;
4!
3276
        }
3277

3278
        this.length = i + len;
5✔
3279
        this.offset = 0;
3✔
3280

3281
        return true;
2✔
3282
    }
3283

3284
    public Reader getReader() {
3285
        return null;
×
3286
    }
3287

3288
    protected IOException expect(String expect, int ch) throws IOException {
3289
        if (ch < 0) {
2✔
3290
            return error("expected " + expect + " at end of file");
5✔
3291
        } else {
3292
            offset--;
6✔
3293

3294
            try {
3295
                String context = buildDebugContext(buffer, 0, length, offset);
10✔
3296

3297
                Object obj = readObject();
×
3298

3299
                if (obj != null) {
×
3300
                    return error("expected " + expect
×
3301
                            + " at 0x" + Integer.toHexString(ch & 0xff)
×
3302
                            + " " + obj.getClass().getName() + " (" + obj + ")"
×
3303
                            + "\n  " + context);
3304
                } else {
3305
                    return error("expected " + expect + " at 0x" + Integer.toHexString(ch & 0xff) + " null");
×
3306
                }
3307
            } catch (Exception e) {
1✔
3308
                log.debug(e.toString(), e);
5✔
3309

3310
                return error("expected " + expect + " at 0x" + Integer.toHexString(ch & 0xff));
9✔
3311
            }
3312
        }
3313
    }
3314

3315
    private String buildDebugContext(byte[] buffer, int offset, int length, int errorOffset) {
3316
        StringBuilder sb = new StringBuilder();
4✔
3317

3318
        sb.append("[");
4✔
3319
        for (int i = 0; i < errorOffset; i++) {
5!
3320
            int ch = buffer[offset + i];
×
3321
            addDebugChar(sb, ch);
×
3322
        }
3323
        sb.append("] ");
4✔
3324
        addDebugChar(sb, buffer[offset + errorOffset]);
8✔
3325
        sb.append(" [");
4✔
3326
        for (int i = errorOffset + 1; i < length; i++) {
7!
3327
            int ch = buffer[offset + i];
×
3328
            addDebugChar(sb, ch);
×
3329
        }
3330
        sb.append("]");
4✔
3331

3332
        return sb.toString();
3✔
3333
    }
3334

3335
    private void addDebugChar(StringBuilder sb, int ch) {
3336
        if (ch >= 0x20 && ch < 0x7f) {
6!
3337
            sb.append((char) ch);
6✔
3338
        } else if (ch == '\n') {
×
3339
            sb.append((char) ch);
×
3340
        } else {
3341
            sb.append(String.format("\\x%02x", ch & 0xff));
×
3342
        }
3343
    }
1✔
3344

3345
    protected String codeName(int ch) {
3346
        if (ch < 0) {
×
3347
            return "end of file";
×
3348
        } else {
3349
            return "0x" + Integer.toHexString(ch & 0xff) + " (" + (char) +ch + ")";
×
3350
        }
3351
    }
3352

3353
    protected IOException error(String message) {
3354
        return new HessianProtocolException(message);
5✔
3355
    }
3356

3357
    public void free() {
3358
        reset();
2✔
3359
    }
1✔
3360

3361
    @Override
3362
    public void close() throws IOException {
3363
        InputStream lis = this.is;
3✔
3364
        this.is = null;
3✔
3365

3366
        if (isCloseStreamOnClose && lis != null) {
4!
3367
            lis.close();
2✔
3368
        }
3369
    }
1✔
3370

3371
    class ReadInputStream extends InputStream {
5✔
3372
        boolean isClosed = false;
4✔
3373

3374
        @Override
3375
        public int read() throws IOException {
3376
            if (isClosed) {
3✔
3377
                return -1;
2✔
3378
            }
3379

3380
            int ch = parseByte();
4✔
3381
            if (ch < 0) {
2✔
3382
                isClosed = true;
3✔
3383
            }
3384

3385
            return ch;
2✔
3386
        }
3387

3388
        @Override
3389
        public int read(byte[] buffer, int offset, int length) throws IOException {
3390
            if (isClosed) {
3!
3391
                return -1;
×
3392
            }
3393

3394
            int len = HessianDecoder.this.read(buffer, offset, length);
7✔
3395
            if (len < 0) {
2✔
3396
                isClosed = true;
3✔
3397
            }
3398

3399
            return len;
2✔
3400
        }
3401

3402
        @Override
3403
        public void close() throws IOException {
3404
            while (read() >= 0) {}
3!
3405
        }
1✔
3406
    }
3407
    ;
3408

3409
    static final class ObjectDefinition {
3410
        private final String type;
3411
        private final Deserializer reader;
3412
        private final Object[] fields;
3413
        private final String[] fieldNames;
3414

3415
        ObjectDefinition(String type, Deserializer reader, Object[] fields, String[] fieldNames) {
2✔
3416
            this.type = type;
3✔
3417
            this.reader = reader;
3✔
3418
            this.fields = fields;
3✔
3419
            this.fieldNames = fieldNames;
3✔
3420
        }
1✔
3421

3422
        String getType() {
3423
            return type;
3✔
3424
        }
3425

3426
        Deserializer getReader() {
3427
            return reader;
3✔
3428
        }
3429

3430
        Object[] getFields() {
3431
            return fields;
3✔
3432
        }
3433

3434
        String[] getFieldNames() {
3435
            return fieldNames;
3✔
3436
        }
3437
    }
3438
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc