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

wuwen5 / hessian / 17177490298

23 Aug 2025 03:42PM UTC coverage: 68.416% (+11.8%) from 56.631%
17177490298

push

github

web-flow
refactor: fix sonar S2184 and code clean (#29)

1781 of 2793 branches covered (63.77%)

Branch coverage included in aggregate %.

4152 of 5879 relevant lines covered (70.62%)

3.07 hits per line

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

76.28
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;
11!
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
            case BC_FALSE:
699
                return 0;
2✔
700

701
            case BC_TRUE:
702
                return 1;
2✔
703

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

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

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

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

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

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

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

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

813
            case BC_INT:
814
            case BC_LONG_INT:
815
                return parseInt();
4✔
816

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

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

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

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

875
            case 'L':
876
                return parseLong();
3✔
877

878
            case BC_DOUBLE_ZERO:
879
                return 0;
2✔
880

881
            case BC_DOUBLE_ONE:
882
                return 1;
2✔
883

884
            case BC_DOUBLE_MILL: {
885
                int mills = parseInt();
3✔
886

887
                return (long) (0.001 * mills);
6✔
888
            }
889

890
            case BC_DOUBLE:
891
                return (long) parseDouble();
4✔
892

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

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

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

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

926
            case BC_TRUE:
927
            case BC_DOUBLE_ONE:
928
                return 1;
2✔
929

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

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

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

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

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

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

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

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

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

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

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

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

1095
            case BC_DOUBLE_BYTE:
1096
                return (byte) (offset < length ? buffer[offset++] : read());
19!
1097

1098
            case BC_DOUBLE_SHORT:
1099
                return (short) (256 * read() + read());
10✔
1100

1101
            case BC_DOUBLE_MILL: {
1102
                int mills = parseInt();
3✔
1103

1104
                return 0.001 * mills;
5✔
1105
            }
1106

1107
            case BC_DOUBLE:
1108
                return parseDouble();
3✔
1109

1110
            default:
1111
                throw expect("double", tag);
×
1112
        }
1113
    }
1114

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

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

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

1145
            return parseUTF8Char();
3✔
1146
        } else if (chunkLength == END_OF_DATA) {
4✔
1147
            chunkLength = 0;
3✔
1148
            return -1;
2✔
1149
        }
1150

1151
        int tag = read();
3✔
1152

1153
        switch (tag) {
2!
1154
            case BC_NULL:
1155
                return -1;
2✔
1156

1157
            case BC_STRING:
1158
            case BC_STRING_CHUNK:
1159
                isLastChunk = tag == BC_STRING;
8✔
1160
                chunkLength = (read() << 8) + read();
9✔
1161

1162
                chunkLength--;
6✔
1163
                int value = parseUTF8Char();
3✔
1164

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

1171
                return value;
2✔
1172

1173
            default:
1174
                throw expect("char", tag);
×
1175
        }
1176
    }
1177

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

1184
        if (chunkLength == END_OF_DATA) {
4✔
1185
            chunkLength = 0;
3✔
1186
            return -1;
2✔
1187
        } else if (chunkLength == 0) {
3✔
1188
            int tag = read();
3✔
1189

1190
            switch (tag) {
2✔
1191
                case BC_NULL:
1192
                    return -1;
2✔
1193

1194
                case BC_STRING:
1195
                case BC_STRING_CHUNK:
1196
                    isLastChunk = tag == BC_STRING;
8✔
1197
                    chunkLength = (read() << 8) + read();
9✔
1198
                    break;
1✔
1199

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

1217
                case 0x10:
1218
                case 0x11:
1219
                case 0x12:
1220
                case 0x13:
1221
                case 0x14:
1222
                case 0x15:
1223
                case 0x16:
1224
                case 0x17:
1225
                case 0x18:
1226
                case 0x19:
1227
                case 0x1a:
1228
                case 0x1b:
1229
                case 0x1c:
1230
                case 0x1d:
1231
                case 0x1e:
1232
                case 0x1f:
1233
                    isLastChunk = true;
3✔
1234
                    chunkLength = tag - 0x00;
5✔
1235
                    break;
1✔
1236

1237
                case 0x30:
1238
                case 0x31:
1239
                case 0x32:
1240
                case 0x33:
1241
                    isLastChunk = true;
3✔
1242
                    chunkLength = (tag - 0x30) * 256 + read();
10✔
1243
                    break;
1✔
1244

1245
                default:
1246
                    throw expect("string", tag);
5✔
1247
            }
1248
        }
1249

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

1266
                switch (tag) {
2!
1267
                    case BC_STRING:
1268
                    case BC_STRING_CHUNK:
1269
                        isLastChunk = tag == BC_STRING;
6!
1270
                        chunkLength = (read() << 8) + read();
9✔
1271
                        break;
1✔
1272

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

1290
                    case 0x10:
1291
                    case 0x11:
1292
                    case 0x12:
1293
                    case 0x13:
1294
                    case 0x14:
1295
                    case 0x15:
1296
                    case 0x16:
1297
                    case 0x17:
1298
                    case 0x18:
1299
                    case 0x19:
1300
                    case 0x1a:
1301
                    case 0x1b:
1302
                    case 0x1c:
1303
                    case 0x1d:
1304
                    case 0x1e:
1305
                    case 0x1f:
1306
                        isLastChunk = true;
3✔
1307
                        chunkLength = tag - 0x00;
5✔
1308
                        break;
1✔
1309

1310
                    case 0x30:
1311
                    case 0x31:
1312
                    case 0x32:
1313
                    case 0x33:
1314
                        isLastChunk = true;
×
1315
                        chunkLength = (tag - 0x30) * 256 + read();
×
1316
                        break;
×
1317

1318
                    default:
1319
                        throw expect("string", tag);
×
1320
                }
1321
            }
1✔
1322
        }
1323

1324
        if (readLength == 0) {
2!
1325
            return -1;
×
1326
        } else if (chunkLength > 0 || !isLastChunk) {
6✔
1327
            return readLength;
2✔
1328
        } else {
1329
            chunkLength = END_OF_DATA;
3✔
1330
            return readLength;
2✔
1331
        }
1332
    }
1333

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

1345
        switch (tag) {
2✔
1346
            case BC_NULL:
1347
                return null;
2✔
1348
            case BC_TRUE:
1349
                return "true";
2✔
1350
            case BC_FALSE:
1351
                return "false";
2✔
1352

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

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

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

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

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

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

1453
            case BC_INT:
1454
            case BC_LONG_INT:
1455
                return String.valueOf(parseInt());
4✔
1456

1457
                // direct long
1458
            case 0xd8:
1459
            case 0xd9:
1460
            case 0xda:
1461
            case 0xdb:
1462
            case 0xdc:
1463
            case 0xdd:
1464
            case 0xde:
1465
            case 0xdf:
1466

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

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

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

1515
            case BC_LONG:
1516
                return String.valueOf(parseLong());
4✔
1517

1518
            case BC_DOUBLE_ZERO:
1519
                return "0.0";
2✔
1520

1521
            case BC_DOUBLE_ONE:
1522
                return "1.0";
2✔
1523

1524
            case BC_DOUBLE_BYTE:
1525
                return String.valueOf((byte) (offset < length ? buffer[offset++] : read()));
19!
1526

1527
            case BC_DOUBLE_SHORT:
1528
                return String.valueOf(((short) (256 * read() + read())));
10✔
1529

1530
            case BC_DOUBLE_MILL: {
1531
                int mills = parseInt();
3✔
1532

1533
                return String.valueOf(0.001 * mills);
6✔
1534
            }
1535

1536
            case BC_DOUBLE:
1537
                return String.valueOf(parseDouble());
4✔
1538

1539
            case BC_STRING:
1540
            case BC_STRING_CHUNK:
1541
                isLastChunk = tag == BC_STRING;
7!
1542
                chunkLength = (read() << 8) + read();
9✔
1543

1544
                sbuf.setLength(0);
4✔
1545
                int ch;
1546

1547
                while ((ch = parseChar()) >= 0) {
5✔
1548
                    sbuf.append((char) ch);
7✔
1549
                }
1550

1551
                return sbuf.toString();
4✔
1552

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

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

1590
                sbuf.setLength(0);
4✔
1591

1592
                while ((ch = parseChar()) >= 0) {
5✔
1593
                    sbuf.append((char) ch);
7✔
1594
                }
1595

1596
                return sbuf.toString();
4✔
1597

1598
            case 0x30:
1599
            case 0x31:
1600
            case 0x32:
1601
            case 0x33:
1602
                isLastChunk = true;
3✔
1603
                chunkLength = (tag - 0x30) * 256 + read();
10✔
1604

1605
                sbuf.setLength(0);
4✔
1606

1607
                while ((ch = parseChar()) >= 0) {
5✔
1608
                    sbuf.append((char) ch);
7✔
1609
                }
1610

1611
                return sbuf.toString();
4✔
1612

1613
            default:
1614
                throw expect("string", tag);
5✔
1615
        }
1616
    }
1617

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

1629
        switch (tag) {
2!
1630
            case BC_NULL:
1631
                return null;
2✔
1632

1633
            case BC_BINARY:
1634
            case BC_BINARY_CHUNK:
1635
                isLastChunk = tag == BC_BINARY;
8✔
1636
                chunkLength = (read() << 8) + read();
9✔
1637

1638
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
4✔
1639

1640
                int data;
1641
                while ((data = parseByte()) >= 0) {
5✔
1642
                    bos.write(data);
4✔
1643
                }
1644

1645
                return bos.toByteArray();
3✔
1646

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

1666
                byte[] bytes = new byte[chunkLength];
4✔
1667

1668
                int i = 0;
2✔
1669
                while (i < chunkLength) {
4✔
1670
                    int sublen = read(bytes, 0, chunkLength - i);
9✔
1671

1672
                    if (sublen <= 0) {
2!
1673
                        break;
×
1674
                    }
1675

1676
                    i += sublen;
4✔
1677
                }
1✔
1678

1679
                return bytes;
2✔
1680
            }
1681

1682
            case 0x34:
1683
            case 0x35:
1684
            case 0x36:
1685
            case 0x37: {
1686
                isLastChunk = true;
3✔
1687
                chunkLength = (tag - 0x34) * 256 + read();
10✔
1688

1689
                byte[] bytes = new byte[chunkLength];
4✔
1690

1691
                int i = 0;
2✔
1692
                while (i < chunkLength) {
4✔
1693
                    int sublen = read(bytes, 0, chunkLength - i);
9✔
1694

1695
                    if (sublen <= 0) {
2!
1696
                        break;
×
1697
                    }
1698

1699
                    i += sublen;
4✔
1700
                }
1✔
1701

1702
                return bytes;
2✔
1703
            }
1704

1705
            default:
1706
                throw expect("bytes", tag);
×
1707
        }
1708
    }
1709

1710
    /**
1711
     * Reads a byte from the stream.
1712
     */
1713
    public int readByte() throws IOException {
1714
        if (chunkLength > 0) {
3✔
1715
            chunkLength--;
6✔
1716
            if (chunkLength == 0 && isLastChunk) {
6✔
1717
                chunkLength = END_OF_DATA;
3✔
1718
            }
1719

1720
            return read();
3✔
1721
        } else if (chunkLength == END_OF_DATA) {
4✔
1722
            chunkLength = 0;
3✔
1723
            return -1;
2✔
1724
        }
1725

1726
        int tag = read();
3✔
1727

1728
        switch (tag) {
2!
1729
            case BC_NULL:
1730
                return -1;
2✔
1731

1732
            case BC_BINARY:
1733
            case BC_BINARY_CHUNK: {
1734
                isLastChunk = tag == BC_BINARY;
8✔
1735
                chunkLength = (read() << 8) + read();
9✔
1736

1737
                int value = parseByte();
3✔
1738

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

1745
                return value;
2✔
1746
            }
1747

1748
            case 0x20:
1749
            case 0x21:
1750
            case 0x22:
1751
            case 0x23:
1752
            case 0x24:
1753
            case 0x25:
1754
            case 0x26:
1755
            case 0x27:
1756
            case 0x28:
1757
            case 0x29:
1758
            case 0x2a:
1759
            case 0x2b:
1760
            case 0x2c:
1761
            case 0x2d:
1762
            case 0x2e:
1763
            case 0x2f: {
1764
                isLastChunk = true;
3✔
1765
                chunkLength = tag - 0x20;
5✔
1766

1767
                int value = parseByte();
3✔
1768

1769
                // special code so successive read byte won't
1770
                // be read as a single object.
1771
                if (chunkLength == 0) {
3!
1772
                    chunkLength = END_OF_DATA;
×
1773
                }
1774

1775
                return value;
2✔
1776
            }
1777

1778
            case 0x34:
1779
            case 0x35:
1780
            case 0x36:
1781
            case 0x37: {
1782
                isLastChunk = true;
3✔
1783
                chunkLength = (tag - 0x34) * 256 + read();
10✔
1784

1785
                int value = parseByte();
3✔
1786

1787
                // special code so successive read byte won't
1788
                // be read as a single object.
1789
                if (chunkLength == 0) {
3!
1790
                    chunkLength = END_OF_DATA;
×
1791
                }
1792

1793
                return value;
2✔
1794
            }
1795

1796
            default:
1797
                throw expect("binary", tag);
×
1798
        }
1799
    }
1800

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

1807
        if (chunkLength == END_OF_DATA) {
4!
1808
            chunkLength = 0;
×
1809
            return -1;
×
1810
        } else if (chunkLength == 0) {
3!
1811
            int tag = read();
3✔
1812

1813
            switch (tag) {
2!
1814
                case BC_NULL:
1815
                    return -1;
×
1816

1817
                case BC_BINARY:
1818
                case BC_BINARY_CHUNK:
1819
                    isLastChunk = tag == BC_BINARY;
6!
1820
                    chunkLength = (read() << 8) + read();
9✔
1821
                    break;
1✔
1822

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

1844
                case 0x34:
1845
                case 0x35:
1846
                case 0x36:
1847
                case 0x37: {
1848
                    isLastChunk = true;
×
1849
                    chunkLength = (tag - 0x34) * 256 + read();
×
1850
                    break;
×
1851
                }
1852

1853
                default:
1854
                    throw expect("binary", tag);
×
1855
            }
1856
        }
1857

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

1873
                switch (tag) {
2!
1874
                    case BC_BINARY:
1875
                    case BC_BINARY_CHUNK:
1876
                        isLastChunk = tag == BC_BINARY;
8✔
1877
                        chunkLength = (read() << 8) + read();
9✔
1878
                        break;
1✔
1879

1880
                    default:
1881
                        throw expect("binary", tag);
×
1882
                }
1883
            }
1✔
1884
        }
1885

1886
        if (readLength == 0) {
2!
1887
            return -1;
×
1888
        } else if (chunkLength > 0 || !isLastChunk) {
6!
1889
            return readLength;
×
1890
        } else {
1891
            chunkLength = END_OF_DATA;
3✔
1892
            return readLength;
2✔
1893
        }
1894
    }
1895

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

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

1907
        switch (tag) {
2!
1908
            case BC_NULL:
1909
                return null;
2✔
1910

1911
            case BC_MAP_UNTYPED: {
1912
                Deserializer reader = findSerializerFactory().getDeserializer(cl);
5✔
1913

1914
                return reader.readMap(this);
4✔
1915
            }
1916

1917
            case BC_MAP: {
1918
                String type = readType();
3✔
1919

1920
                // hessian/3bb3
1921
                if ("".equals(type)) {
4!
1922
                    Deserializer reader;
1923
                    reader = findSerializerFactory().getDeserializer(cl);
×
1924

1925
                    return reader.readMap(this);
×
1926
                } else {
1927
                    Deserializer reader;
1928
                    reader = findSerializerFactory().getObjectDeserializer(type, cl);
6✔
1929

1930
                    return reader.readMap(this);
4✔
1931
                }
1932
            }
1933

1934
            case BC_OBJECT_DEF: {
1935
                readObjectDefinition();
2✔
1936

1937
                return readObject(cl);
4✔
1938
            }
1939

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

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

1962
                ObjectDefinition def = classDefs.get(ref);
6✔
1963

1964
                return readObjectInstance(cl, def);
5✔
1965
            }
1966

1967
            case BC_OBJECT: {
1968
                int ref = readInt();
×
1969
                int size = classDefs.size();
×
1970

1971
                if (ref < 0 || size <= ref)
×
1972
                    throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
×
1973

1974
                ObjectDefinition def = classDefs.get(ref);
×
1975

1976
                return readObjectInstance(cl, def);
×
1977
            }
1978

1979
            case BC_LIST_VARIABLE: {
1980
                String type = readType();
×
1981

1982
                Deserializer reader;
1983
                reader = findSerializerFactory().getListDeserializer(type, cl);
×
1984

1985
                return reader.readList(this, -1);
×
1986
            }
1987

1988
            case BC_LIST_FIXED: {
1989
                String type = readType();
3✔
1990
                int len = readInt();
3✔
1991

1992
                Deserializer reader;
1993
                reader = findSerializerFactory().getListDeserializer(type, cl);
6✔
1994

1995
                return reader.readLengthList(this, len);
5✔
1996
            }
1997

1998
            case 0x70:
1999
            case 0x71:
2000
            case 0x72:
2001
            case 0x73:
2002
            case 0x74:
2003
            case 0x75:
2004
            case 0x76:
2005
            case 0x77: {
2006
                int i = tag - 0x70;
4✔
2007

2008
                String type = readType();
3✔
2009

2010
                Deserializer reader;
2011
                reader = findSerializerFactory().getListDeserializer(type, cl);
6✔
2012

2013
                return reader.readLengthList(this, i);
5✔
2014
            }
2015

2016
            case BC_LIST_VARIABLE_UNTYPED: {
2017
                Deserializer reader;
2018
                reader = findSerializerFactory().getListDeserializer(null, cl);
×
2019

2020
                return reader.readList(this, -1);
×
2021
            }
2022

2023
            case BC_LIST_FIXED_UNTYPED: {
2024
                int len = readInt();
×
2025

2026
                Deserializer reader;
2027
                reader = findSerializerFactory().getListDeserializer(null, cl);
×
2028

2029
                return reader.readLengthList(this, len);
×
2030
            }
2031

2032
            case 0x78:
2033
            case 0x79:
2034
            case 0x7a:
2035
            case 0x7b:
2036
            case 0x7c:
2037
            case 0x7d:
2038
            case 0x7e:
2039
            case 0x7f: {
2040
                int i = tag - 0x78;
4✔
2041

2042
                Deserializer reader;
2043
                reader = findSerializerFactory().getListDeserializer(null, cl);
6✔
2044

2045
                return reader.readLengthList(this, i);
5✔
2046
            }
2047

2048
            case BC_REF: {
2049
                int ref = readInt();
3✔
2050

2051
                return refs.get(ref);
5✔
2052
            }
2053
        }
2054

2055
        if (tag >= 0) {
2!
2056
            offset--;
6✔
2057
        }
2058

2059
        return findSerializerFactory().getDeserializer(cl).readObject(this);
7✔
2060
    }
2061

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

2070
        switch (tag) {
2!
2071
            case BC_NULL:
2072
                return null;
2✔
2073

2074
            case BC_TRUE:
2075
                return Boolean.TRUE;
2✔
2076

2077
            case BC_FALSE:
2078
                return Boolean.FALSE;
2✔
2079

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

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

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

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

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

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

2180
            case BC_INT:
2181
                return parseInt();
4✔
2182

2183
                // direct long
2184
            case 0xd8:
2185
            case 0xd9:
2186
            case 0xda:
2187
            case 0xdb:
2188
            case 0xdc:
2189
            case 0xdd:
2190
            case 0xde:
2191
            case 0xdf:
2192

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

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

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

2241
            case BC_LONG_INT:
2242
                return (long) parseInt();
5✔
2243

2244
            case BC_LONG:
2245
                return parseLong();
4✔
2246

2247
            case BC_DOUBLE_ZERO:
2248
                return (double) 0;
3✔
2249

2250
            case BC_DOUBLE_ONE:
2251
                return 1.0;
3✔
2252

2253
            case BC_DOUBLE_BYTE:
2254
                return (double) (byte) read();
6✔
2255

2256
            case BC_DOUBLE_SHORT:
2257
                return (double) (short) (256 * read() + read());
11✔
2258

2259
            case BC_DOUBLE_MILL: {
2260
                int mills = parseInt();
3✔
2261

2262
                return 0.001 * mills;
6✔
2263
            }
2264

2265
            case BC_DOUBLE:
2266
                return parseDouble();
4✔
2267

2268
            case BC_DATE:
2269
                return new Date(parseLong());
6✔
2270

2271
            case BC_DATE_MINUTE:
2272
                return new Date(parseInt() * 60000L);
9✔
2273

2274
            case BC_STRING_CHUNK:
2275
            case BC_STRING: {
2276
                isLastChunk = tag == BC_STRING;
8✔
2277
                chunkLength = (read() << 8) + read();
9✔
2278

2279
                sbuf.setLength(0);
4✔
2280

2281
                parseString(sbuf);
4✔
2282

2283
                return sbuf.toString();
4✔
2284
            }
2285

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

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

2322
                sbuf.setLength(0);
4✔
2323

2324
                parseString(sbuf);
4✔
2325

2326
                return sbuf.toString();
4✔
2327
            }
2328

2329
            case 0x30:
2330
            case 0x31:
2331
            case 0x32:
2332
            case 0x33: {
2333
                isLastChunk = true;
3✔
2334
                chunkLength = (tag - 0x30) * 256 + read();
10✔
2335

2336
                sbuf.setLength(0);
4✔
2337

2338
                parseString(sbuf);
4✔
2339

2340
                return sbuf.toString();
4✔
2341
            }
2342

2343
            case BC_BINARY_CHUNK:
2344
            case BC_BINARY: {
2345
                isLastChunk = tag == BC_BINARY;
6!
2346
                chunkLength = (read() << 8) + read();
9✔
2347

2348
                int data;
2349
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
4✔
2350

2351
                while ((data = parseByte()) >= 0) {
5✔
2352
                    bos.write(data);
4✔
2353
                }
2354

2355
                return bos.toByteArray();
3✔
2356
            }
2357

2358
            case 0x20:
2359
            case 0x21:
2360
            case 0x22:
2361
            case 0x23:
2362
            case 0x24:
2363
            case 0x25:
2364
            case 0x26:
2365
            case 0x27:
2366
            case 0x28:
2367
            case 0x29:
2368
            case 0x2a:
2369
            case 0x2b:
2370
            case 0x2c:
2371
            case 0x2d:
2372
            case 0x2e:
2373
            case 0x2f: {
2374
                isLastChunk = true;
3✔
2375
                int len = tag - 0x20;
4✔
2376
                chunkLength = 0;
3✔
2377

2378
                byte[] data = new byte[len];
3✔
2379

2380
                for (int i = 0; i < len; i++) {
7✔
2381
                    data[i] = (byte) read();
6✔
2382
                }
2383

2384
                return data;
2✔
2385
            }
2386

2387
            case 0x34:
2388
            case 0x35:
2389
            case 0x36:
2390
            case 0x37: {
2391
                isLastChunk = true;
×
2392
                int len = (tag - 0x34) * 256 + read();
×
2393
                chunkLength = 0;
×
2394

2395
                byte[] bytes = new byte[len];
×
2396

2397
                for (int i = 0; i < len; i++) {
×
2398
                    bytes[i] = (byte) read();
×
2399
                }
2400

2401
                return bytes;
×
2402
            }
2403

2404
            case BC_LIST_VARIABLE: {
2405
                // variable length list
2406
                String type = readType();
3✔
2407

2408
                return findSerializerFactory().readList(this, -1, type);
7✔
2409
            }
2410

2411
            case BC_LIST_VARIABLE_UNTYPED: {
2412
                return findSerializerFactory().readList(this, -1, null);
7✔
2413
            }
2414

2415
            case BC_LIST_FIXED: {
2416
                // fixed length lists
2417
                String type = readType();
3✔
2418
                int len = readInt();
3✔
2419

2420
                Deserializer reader;
2421
                reader = findSerializerFactory().getListDeserializer(type, null);
6✔
2422

2423
                return reader.readLengthList(this, len);
5✔
2424
            }
2425

2426
            case BC_LIST_FIXED_UNTYPED: {
2427
                // fixed length lists
2428
                int len = readInt();
×
2429

2430
                Deserializer reader;
2431
                reader = findSerializerFactory().getListDeserializer(null, null);
×
2432

2433
                return reader.readLengthList(this, len);
×
2434
            }
2435

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

2449
                Deserializer reader;
2450
                reader = findSerializerFactory().getListDeserializer(type, null);
6✔
2451

2452
                return reader.readLengthList(this, len);
5✔
2453
            }
2454

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

2467
                Deserializer reader;
2468
                reader = findSerializerFactory().getListDeserializer(null, null);
6✔
2469

2470
                return reader.readLengthList(this, len);
5✔
2471
            }
2472

2473
            case BC_MAP_UNTYPED: {
2474
                return findSerializerFactory().readMap(this, null);
6✔
2475
            }
2476

2477
            case BC_MAP: {
2478
                String type = readType();
3✔
2479

2480
                return findSerializerFactory().readMap(this, type);
6✔
2481
            }
2482

2483
            case BC_OBJECT_DEF: {
2484
                readObjectDefinition();
2✔
2485

2486
                return readObject();
3✔
2487
            }
2488

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

2507
                if (classDefs.size() <= ref) {
5!
2508
                    throw error("No classes defined at reference '" + Integer.toHexString(tag) + "'");
×
2509
                }
2510

2511
                ObjectDefinition def = classDefs.get(ref);
6✔
2512

2513
                return readObjectInstance(null, def);
5✔
2514
            }
2515

2516
            case BC_OBJECT: {
2517
                int ref = readInt();
×
2518

2519
                if (classDefs.size() <= ref) {
×
2520
                    throw error("Illegal object reference #" + ref);
×
2521
                }
2522

2523
                ObjectDefinition def = classDefs.get(ref);
×
2524

2525
                return readObjectInstance(null, def);
×
2526
            }
2527

2528
            case BC_REF: {
2529
                int ref = readInt();
×
2530

2531
                return refs.get(ref);
×
2532
            }
2533

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

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

2554
        SerializerFactory factory = findSerializerFactory();
3✔
2555

2556
        Deserializer reader = factory.getObjectDeserializer(type, null);
5✔
2557

2558
        Object[] fields = reader.createFields(len);
4✔
2559
        String[] fieldNames = new String[len];
3✔
2560

2561
        for (int i = 0; i < len; i++) {
7✔
2562
            String name = readString();
3✔
2563

2564
            fields[i] = reader.createField(name);
6✔
2565
            fieldNames[i] = name;
4✔
2566
        }
2567

2568
        ObjectDefinition def = new ObjectDefinition(type, reader, fields, fieldNames);
8✔
2569

2570
        classDefs.add(def);
5✔
2571
    }
1✔
2572

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

2578
        SerializerFactory factory = findSerializerFactory();
3✔
2579

2580
        if (cl != reader.getType() && cl != null) {
6✔
2581
            reader = factory.getObjectDeserializer(type, cl);
5✔
2582

2583
            return reader.readObject(this, def.getFieldNames());
6✔
2584
        } else {
2585
            return reader.readObject(this, fields);
5✔
2586
        }
2587
    }
2588

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

2597
        return resolveRemote(type, url);
×
2598
    }
2599

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

2607
        return refs.get(value);
×
2608
    }
2609

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

2618
    /**
2619
     * Reads the start of a list.
2620
     */
2621
    @Override
2622
    public int readMapStart() throws IOException {
2623
        return read();
3✔
2624
    }
2625

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

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

2638
            if (code >= 0) {
×
2639
                offset--;
×
2640
            }
2641
        }
2642

2643
        return (code < 0 || code == 'Z');
9!
2644
    }
2645

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

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

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

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

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

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

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

2695
        refs.add(ref);
5✔
2696

2697
        return refs.size() - 1;
6✔
2698
    }
2699

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

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

2716
    public void reset() {
2717
        resetReferences();
2✔
2718

2719
        classDefs.clear();
3✔
2720
        types.clear();
3✔
2721
    }
1✔
2722

2723
    public void resetBuffer() {
2724
        int i = this.offset;
×
2725
        this.offset = 0;
×
2726

2727
        int len = this.length;
×
2728
        this.length = 0;
×
2729

2730
        if (len > 0 && i != len) {
×
2731
            throw new IllegalStateException("offset=" + i + " length=" + len);
×
2732
        }
2733
    }
×
2734

2735
    public Object readStreamingObject() throws IOException {
2736
        if (refs != null) {
3!
2737
            refs.clear();
3✔
2738
        }
2739

2740
        return readObject();
3✔
2741
    }
2742

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

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

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

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

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

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

2812
                if (types == null) {
3!
2813
                    types = new ArrayList<>();
×
2814
                }
2815

2816
                types.add(type);
5✔
2817

2818
                return type;
2✔
2819
            }
2820

2821
            default: {
2822
                int ref = readInt();
3✔
2823

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

2829
                return types.get(ref);
6✔
2830
            }
2831
        }
2832
    }
2833

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

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

2856
        if (i + 3 < length) {
6!
2857
            byte[] buf = this.buffer;
3✔
2858

2859
            int b32 = buf[i] & 0xff;
6✔
2860
            int b24 = buf[i + 1] & 0xff;
8✔
2861
            int b16 = buf[i + 2] & 0xff;
8✔
2862
            int b8 = buf[i + 3] & 0xff;
8✔
2863

2864
            this.offset = i + 4;
5✔
2865

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

2873
            return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
×
2874
        }
2875
    }
2876

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

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

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

2907
        return Double.longBitsToDouble(bits);
3✔
2908
    }
2909

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

2916
            int i = chunkLength;
3✔
2917
            chunkLength = 0;
3✔
2918

2919
            while (i-- > 0) {
3✔
2920
                sbuf.append((char) parseUTF8Char());
7✔
2921
            }
2922
        }
1✔
2923
    }
2924

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

2935
        chunkLength--;
6✔
2936

2937
        return parseUTF8Char();
3✔
2938
    }
2939

2940
    private boolean parseChunkLength() throws IOException {
2941
        if (isLastChunk) {
3✔
2942
            return false;
2✔
2943
        }
2944

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

2947
        switch (code) {
2!
2948
            case BC_STRING_CHUNK:
2949
                isLastChunk = false;
×
2950

2951
                chunkLength = (read() << 8) + read();
×
2952
                break;
×
2953

2954
            case BC_STRING:
2955
                isLastChunk = true;
3✔
2956

2957
                chunkLength = (read() << 8) + read();
9✔
2958
                break;
1✔
2959

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

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

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

3005
            default:
3006
                throw expect("string", code);
×
3007
        }
3008

3009
        return true;
2✔
3010
    }
3011

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

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

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

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

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

3043
            int code = read();
3✔
3044

3045
            switch (code) {
2!
3046
                case BC_BINARY_CHUNK:
3047
                    isLastChunk = false;
3✔
3048

3049
                    chunkLength = (read() << 8) + read();
9✔
3050
                    break;
1✔
3051

3052
                case BC_BINARY:
3053
                    isLastChunk = true;
3✔
3054

3055
                    chunkLength = (read() << 8) + read();
9✔
3056
                    break;
1✔
3057

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

3076
                    chunkLength = code - 0x20;
5✔
3077
                    break;
1✔
3078

3079
                case 0x34:
3080
                case 0x35:
3081
                case 0x36:
3082
                case 0x37:
3083
                    isLastChunk = true;
3✔
3084
                    chunkLength = (code - 0x34) * 256 + read();
10✔
3085
                    break;
1✔
3086

3087
                default:
3088
                    throw expect("byte[]", code);
×
3089
            }
3090
        }
1✔
3091

3092
        chunkLength--;
6✔
3093

3094
        return read();
3✔
3095
    }
3096

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

3104
        switch (tag) {
2!
3105
            case BC_NULL:
3106
                return null;
2✔
3107

3108
            case BC_BINARY:
3109
            case BC_BINARY_CHUNK:
3110
                isLastChunk = tag == BC_BINARY;
×
3111
                chunkLength = (read() << 8) + read();
×
3112
                break;
×
3113

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

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

3142
            default:
3143
                throw expect("binary", tag);
×
3144
        }
3145

3146
        return new ReadInputStream();
5✔
3147
    }
3148

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

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

3161
                int code = read();
×
3162

3163
                switch (code) {
×
3164
                    case BC_BINARY_CHUNK:
3165
                        isLastChunk = false;
×
3166

3167
                        chunkLength = (read() << 8) + read();
×
3168
                        break;
×
3169

3170
                    case BC_BINARY:
3171
                        isLastChunk = true;
×
3172

3173
                        chunkLength = (read() << 8) + read();
×
3174
                        break;
×
3175

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

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

3204
                    default:
3205
                        throw expect("byte[]", code);
×
3206
                }
3207
            }
×
3208

3209
            int sublen = chunkLength;
3✔
3210
            if (length < sublen) {
3!
3211
                sublen = length;
×
3212
            }
3213

3214
            if (this.length <= this.offset && !readBuffer()) {
5!
3215
                return -1;
×
3216
            }
3217

3218
            if (this.length - this.offset < sublen) {
7!
3219
                sublen = this.length - this.offset;
×
3220
            }
3221

3222
            System.arraycopy(this.buffer, this.offset, buffer, offset, sublen);
8✔
3223

3224
            this.offset += sublen;
6✔
3225

3226
            offset += sublen;
4✔
3227
            readLength += sublen;
4✔
3228
            length -= sublen;
4✔
3229
            chunkLength -= sublen;
6✔
3230
        }
1✔
3231

3232
        return readLength;
2✔
3233
    }
3234

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

3244
        return buffer[offset++] & 0xff;
13✔
3245
    }
3246

3247
    protected void unread() {
3248
        if (offset <= 0) {
×
3249
            throw new IllegalStateException();
×
3250
        }
3251

3252
        offset--;
×
3253
    }
×
3254

3255
    private boolean readBuffer() throws IOException {
3256
        byte[] bytes = this.buffer;
3✔
3257
        int i = this.offset;
3✔
3258

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

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

3268
        if (len <= 0) {
2✔
3269
            this.length = i;
3✔
3270
            this.offset = 0;
3✔
3271

3272
            return i > 0;
4!
3273
        }
3274

3275
        this.length = i + len;
5✔
3276
        this.offset = 0;
3✔
3277

3278
        return true;
2✔
3279
    }
3280

3281
    public Reader getReader() {
3282
        return null;
×
3283
    }
3284

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

3291
            try {
3292
                String context = buildDebugContext(buffer, 0, length, offset);
10✔
3293

3294
                Object obj = readObject();
×
3295

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

3307
                return error("expected " + expect + " at 0x" + Integer.toHexString(ch & 0xff));
9✔
3308
            }
3309
        }
3310
    }
3311

3312
    private String buildDebugContext(byte[] buffer, int offset, int length, int errorOffset) {
3313
        StringBuilder sb = new StringBuilder();
4✔
3314

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

3329
        return sb.toString();
3✔
3330
    }
3331

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

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

3350
    protected IOException error(String message) {
3351
        return new HessianProtocolException(message);
5✔
3352
    }
3353

3354
    public void free() {
3355
        reset();
2✔
3356
    }
1✔
3357

3358
    @Override
3359
    public void close() throws IOException {
3360
        InputStream lis = this.is;
3✔
3361
        this.is = null;
3✔
3362

3363
        if (isCloseStreamOnClose && lis != null) {
4!
3364
            lis.close();
2✔
3365
        }
3366
    }
1✔
3367

3368
    class ReadInputStream extends InputStream {
5✔
3369
        boolean isClosed = false;
4✔
3370

3371
        @Override
3372
        public int read() throws IOException {
3373
            if (isClosed) {
3✔
3374
                return -1;
2✔
3375
            }
3376

3377
            int ch = parseByte();
4✔
3378
            if (ch < 0) {
2✔
3379
                isClosed = true;
3✔
3380
            }
3381

3382
            return ch;
2✔
3383
        }
3384

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

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

3396
            return len;
2✔
3397
        }
3398

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

3406
    static final class ObjectDefinition {
3407
        private final String type;
3408
        private final Deserializer reader;
3409
        private final Object[] fields;
3410
        private final String[] fieldNames;
3411

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

3419
        String getType() {
3420
            return type;
3✔
3421
        }
3422

3423
        Deserializer getReader() {
3424
            return reader;
3✔
3425
        }
3426

3427
        Object[] getFields() {
3428
            return fields;
3✔
3429
        }
3430

3431
        String[] getFieldNames() {
3432
            return fieldNames;
3✔
3433
        }
3434
    }
3435
}
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