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

wuwen5 / hessian / 17803828826

15 Sep 2025 01:09AM UTC coverage: 69.283% (+0.2%) from 69.121%
17803828826

push

github

web-flow
perf(calendar): performance optimization of calendar serialization and deserialization (#44)

1830 of 2837 branches covered (64.5%)

Branch coverage included in aggregate %.

4226 of 5904 relevant lines covered (71.58%)

3.12 hits per line

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

76.29
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 = 8 * 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
        if (dIs != null) {
3✔
143
            dIs.initPacket(is);
4✔
144
            is = dIs;
3✔
145
        }
146

147
        this.is = is;
3✔
148
    }
1✔
149

150
    /**
151
     * Gets the serializer factory.
152
     */
153
    public SerializerFactory getSerializerFactory() {
154
        // the default serializer factory cannot be modified by external
155
        // callers
156
        if (serializerFactory == defaultSerializerFactory) {
5!
157
            serializerFactory = new SerializerFactory();
5✔
158
        }
159

160
        return serializerFactory;
3✔
161
    }
162

163
    /**
164
     * Gets the serializer factory.
165
     */
166
    protected final SerializerFactory findSerializerFactory() {
167
        SerializerFactory factory = serializerFactory;
3✔
168

169
        if (factory == null) {
2✔
170
            factory = SerializerFactory.createDefault();
2✔
171
            defaultSerializerFactory = factory;
3✔
172
            serializerFactory = factory;
3✔
173
        }
174

175
        return factory;
2✔
176
    }
177

178
    public void allow(String pattern) {
179
        ClassFactory factory = getSerializerFactory().getClassFactory();
4✔
180

181
        factory.allow(pattern);
3✔
182
    }
1✔
183

184
    public static void setCloseStreamOnClose(boolean isClose) {
185
        isCloseStreamOnClose = isClose;
2✔
186
    }
1✔
187

188
    public static boolean isCloseStreamOnClose() {
189
        return isCloseStreamOnClose;
2✔
190
    }
191

192
    @Override
193
    public void init(InputStream is) {
194
        if (dIs != null) {
3!
195
            dIs.initPacket(is);
4✔
196
            is = dIs;
3✔
197
        }
198

199
        this.is = is;
3✔
200

201
        reset();
2✔
202
    }
1✔
203

204
    public void initPacket(InputStream is) {
205
        if (dIs != null) {
3!
206
            dIs.initPacket(is);
4✔
207
            is = dIs;
3✔
208
        }
209

210
        this.is = is;
3✔
211

212
        resetReferences();
2✔
213
    }
1✔
214

215
    /**
216
     * Reads a null
217
     *
218
     * <pre>
219
     * N
220
     * </pre>
221
     */
222
    @Override
223
    public void readNull() throws IOException {
224
        int tag = read();
3✔
225

226
        if (tag == BC_NULL) {
3✔
227
            return;
1✔
228
        }
229
        throw expect("null", tag);
5✔
230
    }
231

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

244
        switch (tag) {
2✔
245
            case BC_TRUE:
246
                return true;
2✔
247
            case BC_FALSE:
248
                return false;
2✔
249

250
                // direct integer
251
            case 0x80:
252
            case 0x81:
253
            case 0x82:
254
            case 0x83:
255
            case 0x84:
256
            case 0x85:
257
            case 0x86:
258
            case 0x87:
259
            case 0x88:
260
            case 0x89:
261
            case 0x8a:
262
            case 0x8b:
263
            case 0x8c:
264
            case 0x8d:
265
            case 0x8e:
266
            case 0x8f:
267

268
            case 0x90:
269
            case 0x91:
270
            case 0x92:
271
            case 0x93:
272
            case 0x94:
273
            case 0x95:
274
            case 0x96:
275
            case 0x97:
276
            case 0x98:
277
            case 0x99:
278
            case 0x9a:
279
            case 0x9b:
280
            case 0x9c:
281
            case 0x9d:
282
            case 0x9e:
283
            case 0x9f:
284

285
            case 0xa0:
286
            case 0xa1:
287
            case 0xa2:
288
            case 0xa3:
289
            case 0xa4:
290
            case 0xa5:
291
            case 0xa6:
292
            case 0xa7:
293
            case 0xa8:
294
            case 0xa9:
295
            case 0xaa:
296
            case 0xab:
297
            case 0xac:
298
            case 0xad:
299
            case 0xae:
300
            case 0xaf:
301

302
            case 0xb0:
303
            case 0xb1:
304
            case 0xb2:
305
            case 0xb3:
306
            case 0xb4:
307
            case 0xb5:
308
            case 0xb6:
309
            case 0xb7:
310
            case 0xb8:
311
            case 0xb9:
312
            case 0xba:
313
            case 0xbb:
314
            case 0xbc:
315
            case 0xbd:
316
            case 0xbe:
317
            case 0xbf:
318
                return tag != BC_INT_ZERO;
5!
319

320
                // INT_BYTE = 0
321
            case 0xc8:
322
                return read() != 0;
6!
323

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

343
                // INT_SHORT = 0
344
            case BC_INT_SHORT_ZERO:
345
                return (256 * read() + read()) != 0;
11!
346

347
                // INT_SHORT != 0
348
            case 0xd0:
349
            case 0xd1:
350
            case 0xd2:
351
            case 0xd3:
352
            case 0xd5:
353
            case 0xd6:
354
            case 0xd7:
355
                read();
3✔
356
                read();
3✔
357
                return true;
2✔
358

359
            case 'I':
360
                return parseInt() != 0;
6!
361

362
            case 0xd8:
363
            case 0xd9:
364
            case 0xda:
365
            case 0xdb:
366
            case 0xdc:
367
            case 0xdd:
368
            case 0xde:
369
            case 0xdf:
370

371
            case 0xe0:
372
            case 0xe1:
373
            case 0xe2:
374
            case 0xe3:
375
            case 0xe4:
376
            case 0xe5:
377
            case 0xe6:
378
            case 0xe7:
379
            case 0xe8:
380
            case 0xe9:
381
            case 0xea:
382
            case 0xeb:
383
            case 0xec:
384
            case 0xed:
385
            case 0xee:
386
            case 0xef:
387
                return tag != BC_LONG_ZERO;
5!
388

389
                // LONG_BYTE = 0
390
            case BC_LONG_BYTE_ZERO:
391
                return read() != 0;
6!
392

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

412
                // LONG_SHORT = 0
413
            case BC_LONG_SHORT_ZERO:
414
                return (256 * read() + read()) != 0;
11!
415

416
                // LONG_SHORT != 0
417
            case 0x38:
418
            case 0x39:
419
            case 0x3a:
420
            case 0x3b:
421
            case 0x3d:
422
            case 0x3e:
423
            case 0x3f:
424
                read();
3✔
425
                read();
3✔
426
                return true;
2✔
427

428
            case BC_LONG_INT:
429
                return (0x1000000L * read() + 0x10000L * read() + 0x100 * read() + read()) != 0;
27!
430

431
            case BC_LONG:
432
                return parseLong() != 0;
8!
433

434
            case BC_DOUBLE_ZERO:
435
                return false;
2✔
436

437
            case BC_DOUBLE_ONE:
438
                return true;
2✔
439

440
            case BC_DOUBLE_BYTE:
441
                return read() != 0;
6!
442

443
            case BC_DOUBLE_SHORT:
444
                return (0x100 * read() + read()) != 0;
11!
445

446
            case BC_DOUBLE_MILL: {
447
                int mills = parseInt();
3✔
448

449
                return mills != 0;
5!
450
            }
451

452
            case BC_DOUBLE:
453
                return parseDouble() != 0.0;
8!
454

455
            case BC_NULL:
456
                return false;
2✔
457

458
            default:
459
                throw expect("boolean", tag);
5✔
460
        }
461
    }
462

463
    /**
464
     * Reads a short
465
     *
466
     * <pre>
467
     * I b32 b24 b16 b8
468
     * </pre>
469
     */
470
    public short readShort() throws IOException {
471
        return (short) readInt();
4✔
472
    }
473

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

486
        switch (tag) {
2✔
487
            case BC_NULL:
488
                return 0;
2✔
489

490
            case BC_FALSE:
491
                return 0;
2✔
492

493
            case BC_TRUE:
494
                return 1;
2✔
495

496
                // direct integer
497
            case 0x80:
498
            case 0x81:
499
            case 0x82:
500
            case 0x83:
501
            case 0x84:
502
            case 0x85:
503
            case 0x86:
504
            case 0x87:
505
            case 0x88:
506
            case 0x89:
507
            case 0x8a:
508
            case 0x8b:
509
            case 0x8c:
510
            case 0x8d:
511
            case 0x8e:
512
            case 0x8f:
513

514
            case 0x90:
515
            case 0x91:
516
            case 0x92:
517
            case 0x93:
518
            case 0x94:
519
            case 0x95:
520
            case 0x96:
521
            case 0x97:
522
            case 0x98:
523
            case 0x99:
524
            case 0x9a:
525
            case 0x9b:
526
            case 0x9c:
527
            case 0x9d:
528
            case 0x9e:
529
            case 0x9f:
530

531
            case 0xa0:
532
            case 0xa1:
533
            case 0xa2:
534
            case 0xa3:
535
            case 0xa4:
536
            case 0xa5:
537
            case 0xa6:
538
            case 0xa7:
539
            case 0xa8:
540
            case 0xa9:
541
            case 0xaa:
542
            case 0xab:
543
            case 0xac:
544
            case 0xad:
545
            case 0xae:
546
            case 0xaf:
547

548
            case 0xb0:
549
            case 0xb1:
550
            case 0xb2:
551
            case 0xb3:
552
            case 0xb4:
553
            case 0xb5:
554
            case 0xb6:
555
            case 0xb7:
556
            case 0xb8:
557
            case 0xb9:
558
            case 0xba:
559
            case 0xbb:
560
            case 0xbc:
561
            case 0xbd:
562
            case 0xbe:
563
            case 0xbf:
564
                return tag - BC_INT_ZERO;
4✔
565

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

585
                /* short int */
586
            case 0xd0:
587
            case 0xd1:
588
            case 0xd2:
589
            case 0xd3:
590
            case 0xd4:
591
            case 0xd5:
592
            case 0xd6:
593
            case 0xd7:
594
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
14✔
595

596
            case 'I':
597
            case BC_LONG_INT:
598
                return ((read() << 24) + (read() << 16) + (read() << 8) + read());
18✔
599

600
                // direct long
601
            case 0xd8:
602
            case 0xd9:
603
            case 0xda:
604
            case 0xdb:
605
            case 0xdc:
606
            case 0xdd:
607
            case 0xde:
608
            case 0xdf:
609

610
            case 0xe0:
611
            case 0xe1:
612
            case 0xe2:
613
            case 0xe3:
614
            case 0xe4:
615
            case 0xe5:
616
            case 0xe6:
617
            case 0xe7:
618
            case 0xe8:
619
            case 0xe9:
620
            case 0xea:
621
            case 0xeb:
622
            case 0xec:
623
            case 0xed:
624
            case 0xee:
625
            case 0xef:
626
                return tag - BC_LONG_ZERO;
4✔
627

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

647
                /* short long */
648
            case 0x38:
649
            case 0x39:
650
            case 0x3a:
651
            case 0x3b:
652
            case 0x3c:
653
            case 0x3d:
654
            case 0x3e:
655
            case 0x3f:
656
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
14✔
657

658
            case BC_LONG:
659
                return (int) parseLong();
4✔
660

661
            case BC_DOUBLE_ZERO:
662
                return 0;
2✔
663

664
            case BC_DOUBLE_ONE:
665
                return 1;
2✔
666

667
                // case LONG_BYTE:
668
            case BC_DOUBLE_BYTE:
669
                return (byte) (offset < length ? buffer[offset++] : read());
18!
670

671
                // case INT_SHORT:
672
                // case LONG_SHORT:
673
            case BC_DOUBLE_SHORT:
674
                return (short) (256 * read() + read());
9✔
675

676
            case BC_DOUBLE_MILL: {
677
                int mills = parseInt();
3✔
678

679
                return (int) (0.001 * mills);
6✔
680
            }
681

682
            case BC_DOUBLE:
683
                return (int) parseDouble();
4✔
684

685
            default:
686
                throw expect("integer", tag);
5✔
687
        }
688
    }
689

690
    /**
691
     * Reads a long
692
     *
693
     * <pre>
694
     * L b64 b56 b48 b40 b32 b24 b16 b8
695
     * </pre>
696
     */
697
    @Override
698
    public long readLong() throws IOException {
699
        int tag = read();
3✔
700

701
        switch (tag) {
2!
702
            case BC_NULL:
703
            case BC_FALSE:
704
                return 0;
2✔
705

706
            case BC_TRUE:
707
                return 1;
2✔
708

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

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

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

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

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

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

809
                // case LONG_BYTE:
810
            case BC_DOUBLE_BYTE:
811
                return (byte) (offset < length ? buffer[offset++] : read());
19!
812

813
                // case INT_SHORT:
814
                // case LONG_SHORT:
815
            case BC_DOUBLE_SHORT:
816
                return (short) (256 * read() + read());
10✔
817

818
            case BC_INT:
819
            case BC_LONG_INT:
820
                return parseInt();
4✔
821

822
                // direct long
823
            case 0xd8:
824
            case 0xd9:
825
            case 0xda:
826
            case 0xdb:
827
            case 0xdc:
828
            case 0xdd:
829
            case 0xde:
830
            case 0xdf:
831

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

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

869
                /* short long */
870
            case 0x38:
871
            case 0x39:
872
            case 0x3a:
873
            case 0x3b:
874
            case 0x3c:
875
            case 0x3d:
876
            case 0x3e:
877
            case 0x3f:
878
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256L * read() + read();
17✔
879

880
            case 'L':
881
                return parseLong();
3✔
882

883
            case BC_DOUBLE_ZERO:
884
                return 0;
2✔
885

886
            case BC_DOUBLE_ONE:
887
                return 1;
2✔
888

889
            case BC_DOUBLE_MILL: {
890
                int mills = parseInt();
3✔
891

892
                return (long) (0.001 * mills);
6✔
893
            }
894

895
            case BC_DOUBLE:
896
                return (long) parseDouble();
4✔
897

898
            default:
899
                throw expect("long", tag);
×
900
        }
901
    }
902

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

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

925
        switch (tag) {
2!
926
            case BC_NULL:
927
            case BC_FALSE:
928
            case BC_DOUBLE_ZERO:
929
                return 0;
2✔
930

931
            case BC_TRUE:
932
            case BC_DOUBLE_ONE:
933
                return 1;
2✔
934

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

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

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

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

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

1024
                /* short int */
1025
            case 0xd0:
1026
            case 0xd1:
1027
            case 0xd2:
1028
            case 0xd3:
1029
            case 0xd4:
1030
            case 0xd5:
1031
            case 0xd6:
1032
            case 0xd7:
1033
                return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + (double) read();
16✔
1034

1035
            case BC_INT:
1036
            case BC_LONG_INT:
1037
                return parseInt();
4✔
1038

1039
                // direct long
1040
            case 0xd8:
1041
            case 0xd9:
1042
            case 0xda:
1043
            case 0xdb:
1044
            case 0xdc:
1045
            case 0xdd:
1046
            case 0xde:
1047
            case 0xdf:
1048

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

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

1086
                /* short long */
1087
            case 0x38:
1088
            case 0x39:
1089
            case 0x3a:
1090
            case 0x3b:
1091
            case 0x3c:
1092
            case 0x3d:
1093
            case 0x3e:
1094
            case 0x3f:
1095
                return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + (double) read();
16✔
1096

1097
            case BC_LONG:
1098
                return parseLong();
4✔
1099

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

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

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

1109
                return 0.001 * mills;
5✔
1110
            }
1111

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

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

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

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

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

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

1156
        int tag = read();
3✔
1157

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

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

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

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

1176
                return value;
2✔
1177

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

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

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

1195
            switch (tag) {
2✔
1196
                case BC_NULL:
1197
                    return -1;
2✔
1198

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

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

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

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

1250
                default:
1251
                    throw expect("string", tag);
5✔
1252
            }
1253
        }
1254

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

1271
                switch (tag) {
2!
1272
                    case BC_STRING:
1273
                    case BC_STRING_CHUNK:
1274
                        isLastChunk = tag == BC_STRING;
6!
1275
                        chunkLength = (read() << 8) + read();
9✔
1276
                        break;
1✔
1277

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1556
                return sbuf.toString();
4✔
1557

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

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

1595
                sbuf.setLength(0);
4✔
1596

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

1601
                return sbuf.toString();
4✔
1602

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

1610
                sbuf.setLength(0);
4✔
1611

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

1616
                return sbuf.toString();
4✔
1617

1618
            default:
1619
                throw expect("string", tag);
5✔
1620
        }
1621
    }
1622

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

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

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

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

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

1650
                return bos.toByteArray();
3✔
1651

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

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

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

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

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

1684
                return bytes;
2✔
1685
            }
1686

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

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

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

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

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

1707
                return bytes;
2✔
1708
            }
1709

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

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

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

1731
        int tag = read();
3✔
1732

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

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

1742
                int value = parseByte();
3✔
1743

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

1750
                return value;
2✔
1751
            }
1752

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

1772
                int value = parseByte();
3✔
1773

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

1780
                return value;
2✔
1781
            }
1782

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

1790
                int value = parseByte();
3✔
1791

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

1798
                return value;
2✔
1799
            }
1800

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1922
            case BC_MAP: {
1923
                String type = readType();
3✔
1924

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

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

1935
                    return reader.readMap(this);
4✔
1936
                }
1937
            }
1938

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2013
                String type = readType();
3✔
2014

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2255
            case BC_DOUBLE_ONE:
2256
                return 1.0;
3✔
2257

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

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

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

2267
                return 0.001 * mills;
6✔
2268
            }
2269

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

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

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

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

2284
                sbuf.setLength(0);
4✔
2285

2286
                parseString(sbuf);
4✔
2287

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

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

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

2327
                sbuf.setLength(0);
4✔
2328

2329
                parseString(sbuf);
4✔
2330

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

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

2341
                sbuf.setLength(0);
4✔
2342

2343
                parseString(sbuf);
4✔
2344

2345
                return sbuf.toString();
4✔
2346
            }
2347

2348
            case BC_BINARY_CHUNK:
2349
            case BC_BINARY: {
2350
                isLastChunk = tag == BC_BINARY;
6!
2351
                chunkLength = (read() << 8) + read();
9✔
2352

2353
                int data;
2354
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
4✔
2355

2356
                while ((data = parseByte()) >= 0) {
5✔
2357
                    bos.write(data);
4✔
2358
                }
2359

2360
                return bos.toByteArray();
3✔
2361
            }
2362

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

2383
                byte[] data = new byte[len];
3✔
2384

2385
                for (int i = 0; i < len; i++) {
7✔
2386
                    data[i] = (byte) read();
6✔
2387
                }
2388

2389
                return data;
2✔
2390
            }
2391

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

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

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

2406
                return bytes;
×
2407
            }
2408

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2491
                return readObject();
3✔
2492
            }
2493

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

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

2516
                ObjectDefinition def = classDefs.get(ref);
6✔
2517

2518
                return readObjectInstance(null, def);
5✔
2519
            }
2520

2521
            case BC_OBJECT: {
2522
                int ref = readInt();
×
2523

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

2528
                ObjectDefinition def = classDefs.get(ref);
×
2529

2530
                return readObjectInstance(null, def);
×
2531
            }
2532

2533
            case BC_REF: {
2534
                int ref = readInt();
×
2535

2536
                return refs.get(ref);
×
2537
            }
2538

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

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

2559
        SerializerFactory factory = findSerializerFactory();
3✔
2560

2561
        Deserializer reader = factory.getObjectDeserializer(type, null);
5✔
2562

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

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

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

2573
        ObjectDefinition def = new ObjectDefinition(type, reader, fields, fieldNames);
8✔
2574

2575
        classDefs.add(def);
5✔
2576
    }
1✔
2577

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

2583
        SerializerFactory factory = findSerializerFactory();
3✔
2584

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

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

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

2602
        return resolveRemote(type, url);
×
2603
    }
2604

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

2612
        return refs.get(value);
×
2613
    }
2614

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

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

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

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

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

2648
        return (code < 0 || code == 'Z');
9!
2649
    }
2650

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

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

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

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

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

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

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

2700
        refs.add(ref);
5✔
2701

2702
        return refs.size() - 1;
6✔
2703
    }
2704

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

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

2721
    public void reset() {
2722
        resetReferences();
2✔
2723

2724
        classDefs.clear();
3✔
2725
        types.clear();
3✔
2726
    }
1✔
2727

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

2732
        int len = this.length;
×
2733
        this.length = 0;
×
2734

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

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

2745
        return readObject();
3✔
2746
    }
2747

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

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

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

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

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

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

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

2821
                types.add(type);
5✔
2822

2823
                return type;
2✔
2824
            }
2825

2826
            default: {
2827
                int ref = readInt();
3✔
2828

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

2834
                return types.get(ref);
6✔
2835
            }
2836
        }
2837
    }
2838

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

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

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

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

2869
            this.offset = i + 4;
5✔
2870

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

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

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

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

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

2912
        return Double.longBitsToDouble(bits);
3✔
2913
    }
2914

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

2921
            int i = chunkLength;
3✔
2922
            chunkLength = 0;
3✔
2923

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

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

2940
        chunkLength--;
6✔
2941

2942
        return parseUTF8Char();
3✔
2943
    }
2944

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

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

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

2956
                chunkLength = (read() << 8) + read();
×
2957
                break;
×
2958

2959
            case BC_STRING:
2960
                isLastChunk = true;
3✔
2961

2962
                chunkLength = (read() << 8) + read();
9✔
2963
                break;
1✔
2964

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

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

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

3010
            default:
3011
                throw expect("string", code);
×
3012
        }
3013

3014
        return true;
2✔
3015
    }
3016

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

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

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

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

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

3048
            int code = read();
3✔
3049

3050
            switch (code) {
2!
3051
                case BC_BINARY_CHUNK:
3052
                    isLastChunk = false;
3✔
3053

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

3057
                case BC_BINARY:
3058
                    isLastChunk = true;
3✔
3059

3060
                    chunkLength = (read() << 8) + read();
9✔
3061
                    break;
1✔
3062

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

3081
                    chunkLength = code - 0x20;
5✔
3082
                    break;
1✔
3083

3084
                case 0x34:
3085
                case 0x35:
3086
                case 0x36:
3087
                case 0x37:
3088
                    isLastChunk = true;
3✔
3089
                    chunkLength = (code - 0x34) * 256 + read();
10✔
3090
                    break;
1✔
3091

3092
                default:
3093
                    throw expect("byte[]", code);
×
3094
            }
3095
        }
1✔
3096

3097
        chunkLength--;
6✔
3098

3099
        return read();
3✔
3100
    }
3101

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

3109
        switch (tag) {
2!
3110
            case BC_NULL:
3111
                return null;
2✔
3112

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

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

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

3147
            default:
3148
                throw expect("binary", tag);
×
3149
        }
3150

3151
        return new ReadInputStream();
5✔
3152
    }
3153

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

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

3166
                int code = read();
×
3167

3168
                switch (code) {
×
3169
                    case BC_BINARY_CHUNK:
3170
                        isLastChunk = false;
×
3171

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

3175
                    case BC_BINARY:
3176
                        isLastChunk = true;
×
3177

3178
                        chunkLength = (read() << 8) + read();
×
3179
                        break;
×
3180

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

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

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

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

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

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

3227
            System.arraycopy(this.buffer, this.offset, buffer, offset, sublen);
8✔
3228

3229
            this.offset += sublen;
6✔
3230

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

3237
        return readLength;
2✔
3238
    }
3239

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

3249
        return buffer[offset++] & 0xff;
13✔
3250
    }
3251

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

3257
        offset--;
×
3258
    }
×
3259

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

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

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

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

3277
            return i > 0;
4!
3278
        }
3279

3280
        this.length = i + len;
5✔
3281
        this.offset = 0;
3✔
3282

3283
        return true;
2✔
3284
    }
3285

3286
    public Reader getReader() {
3287
        return null;
×
3288
    }
3289

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

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

3299
                Object obj = readObject();
×
3300

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

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

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

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

3334
        return sb.toString();
3✔
3335
    }
3336

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

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

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

3359
    public void free() {
3360
        reset();
2✔
3361
    }
1✔
3362

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

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

3373
    class ReadInputStream extends InputStream {
5✔
3374
        boolean isClosed = false;
4✔
3375

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

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

3387
            return ch;
2✔
3388
        }
3389

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

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

3401
            return len;
2✔
3402
        }
3403

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

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

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

3424
        String getType() {
3425
            return type;
3✔
3426
        }
3427

3428
        Deserializer getReader() {
3429
            return reader;
3✔
3430
        }
3431

3432
        Object[] getFields() {
3433
            return fields;
3✔
3434
        }
3435

3436
        String[] getFieldNames() {
3437
            return fieldNames;
3✔
3438
        }
3439
    }
3440
}
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