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

wuwen5 / hessian / 17023334512

17 Aug 2025 04:22PM UTC coverage: 43.93% (-0.2%) from 44.094%
17023334512

push

github

wuwen5
refactor: code clean,fix sonar java:S1117 and other.

1202 of 2983 branches covered (40.3%)

Branch coverage included in aggregate %.

2865 of 6275 relevant lines covered (45.66%)

1.99 hits per line

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

45.76
hessian2-codec/src/main/java/io/github/wuwen5/hessian/io/HessianEncoder.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 "Burlap", "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 io.github.wuwen5.hessian.util.IdentityIntMap;
52
import java.io.IOException;
53
import java.io.InputStream;
54
import java.io.OutputStream;
55
import java.util.HashMap;
56

57
/**
58
 * Output stream for Hessian 2 requests.
59
 *
60
 * <p>Since HessianOutput does not depend on any classes other than
61
 * in the JDK, it can be extracted independently into a smaller package.
62
 *
63
 * <p>HessianOutput is unbuffered, so any client needs to provide
64
 * its own buffering.
65
 *
66
 * <pre>
67
 * OutputStream os = ...; // from http connection
68
 * Hessian2Output out = new Hessian2Output(os);
69
 * String value;
70
 *
71
 * out.startCall("hello", 1); // start hello call
72
 * out.writeString("arg1");   // write a string argument
73
 * out.completeCall();        // complete the call
74
 * </pre>
75
 */
76
public class HessianEncoder extends AbstractHessianEncoder implements Hessian2Constants {
77

78
    /**
79
     * should match Resin buffer size for perf
80
     */
81
    public static final int SIZE = 8 * 1024;
82

83
    /**
84
     * the output stream/
85
     */
86
    protected OutputStream os;
87

88
    /**
89
     * map of references
90
     */
91
    private final IdentityIntMap refs = new IdentityIntMap(256);
12✔
92

93
    private int refCount = 0;
6✔
94

95
    private boolean isCloseStreamOnClose;
96

97
    /**
98
     * map of classes
99
     */
100
    private final IdentityIntMap classRefs = new IdentityIntMap(256);
12✔
101

102
    /**
103
     * map of types
104
     */
105
    private HashMap<String, Integer> typeRefs;
106

107
    protected final byte[] buffer = new byte[SIZE];
8✔
108
    protected int offset;
109

110
    private boolean isPacket;
111

112
    private boolean isUnshared;
113

114
    /**
115
     * Creates a new Hessian output stream, initialized with an
116
     * underlying output stream.
117
     */
118
    public HessianEncoder() {}
3✔
119

120
    /**
121
     * Creates a new Hessian output stream, initialized with an
122
     * underlying output stream.
123
     *
124
     * @param os the underlying output stream.
125
     */
126
    public HessianEncoder(OutputStream os) {
2✔
127
        init(os);
3✔
128
    }
1✔
129

130
    @Override
131
    public void init(OutputStream os) {
132
        reset();
2✔
133

134
        this.os = os;
3✔
135
    }
1✔
136

137
    public void initPacket(OutputStream os) {
138
        resetReferences();
×
139

140
        this.os = os;
×
141
    }
×
142

143
    public void setCloseStreamOnClose(boolean isClose) {
144
        isCloseStreamOnClose = isClose;
×
145
    }
×
146

147
    public boolean isCloseStreamOnClose() {
148
        return isCloseStreamOnClose;
×
149
    }
150

151
    /**
152
     * Sets hessian to be "unshared", meaning it will not detect
153
     * duplicate or circular references.
154
     */
155
    @Override
156
    public boolean setUnshared(boolean isUnshared) {
157
        boolean oldIsUnshared = this.isUnshared;
×
158

159
        this.isUnshared = isUnshared;
×
160

161
        return oldIsUnshared;
×
162
    }
163

164
    public void writeVersion() throws IOException {
165
        flushIfFull();
×
166

167
        buffer[offset++] = (byte) 'H';
×
168
        buffer[offset++] = (byte) 2;
×
169
        buffer[offset++] = (byte) 0;
×
170
    }
×
171

172
    /**
173
     * Starts a packet
174
     *
175
     * <p>A message contains several objects encapsulated by a length</p>
176
     *
177
     * <pre>
178
     * p x02 x00
179
     * </pre>
180
     */
181
    public void startMessage() throws IOException {
182
        flushIfFull();
×
183

184
        buffer[offset++] = (byte) 'p';
×
185
        buffer[offset++] = (byte) 2;
×
186
        buffer[offset++] = (byte) 0;
×
187
    }
×
188

189
    /**
190
     * Completes reading the message
191
     *
192
     * <p>A successful completion will have a single value:
193
     *
194
     * <pre>
195
     * z
196
     * </pre>
197
     */
198
    public void completeMessage() throws IOException {
199
        flushIfFull();
×
200

201
        buffer[offset++] = (byte) 'z';
×
202
    }
×
203

204
    /**
205
     * Writes a fault.  The fault will be written
206
     * as a descriptive string followed by an object:
207
     *<pre>
208
     * <code>
209
     * F map
210
     * </code>
211
     *
212
     * <code>
213
     * F H
214
     * \x04code
215
     * \x10the fault code
216
     *
217
     * \x07message
218
     * \x11the fault message
219
     *
220
     * \x06detail
221
     * M\xnnjavax.ejb.FinderException
222
     *     ...
223
     * Z
224
     * Z
225
     * </code>
226
     * </pre>
227
     *
228
     * @param code the fault code, a three digit
229
     */
230
    public void writeFault(String code, String message, Object detail) throws IOException {
231
        flushIfFull();
×
232

233
        writeVersion();
×
234

235
        buffer[offset++] = (byte) 'F';
×
236
        buffer[offset++] = (byte) 'H';
×
237

238
        addRef(new Object(), refCount++, false);
×
239

240
        writeString("code");
×
241
        writeString(code);
×
242

243
        writeString("message");
×
244
        writeString(message);
×
245

246
        if (detail != null) {
×
247
            writeString("detail");
×
248
            writeObject(detail);
×
249
        }
250

251
        flushIfFull();
×
252
        buffer[offset++] = (byte) 'Z';
×
253
    }
×
254

255
    /**
256
     * Writes any object to the output stream.
257
     */
258
    @Override
259
    public void writeObject(Object object) throws IOException {
260
        if (object == null) {
2✔
261
            writeNull();
2✔
262
            return;
1✔
263
        }
264

265
        Serializer serializer = findSerializerFactory().getObjectSerializer(object.getClass());
6✔
266

267
        serializer.writeObject(object, this);
4✔
268
    }
1✔
269

270
    /**
271
     * Writes the list header to the stream.  List writers will call
272
     * <code>writeListBegin</code> followed by the list contents and then
273
     * call <code>writeListEnd</code>.
274
     * <p>
275
     *     <pre>
276
     * <code>
277
     * list ::= V type value* Z
278
     *      ::= v type int value*
279
     * </code>
280
     * </pre>
281
     *
282
     * @return true for variable lists, false for fixed lists
283
     */
284
    @Override
285
    public boolean writeListBegin(int length, String type) throws IOException {
286
        flushIfFull();
2✔
287

288
        if (length < 0) {
2!
289
            if (type != null) {
×
290
                buffer[offset++] = (byte) BC_LIST_VARIABLE;
×
291
                writeType(type);
×
292
            } else {
293
                buffer[offset++] = (byte) BC_LIST_VARIABLE_UNTYPED;
×
294
            }
295

296
            return true;
×
297
        } else if (length <= LIST_DIRECT_MAX) {
3✔
298
            if (type != null) {
2✔
299
                buffer[offset++] = (byte) (BC_LIST_DIRECT + length);
14✔
300
                writeType(type);
4✔
301
            } else {
302
                buffer[offset++] = (byte) (BC_LIST_DIRECT_UNTYPED + length);
14✔
303
            }
304

305
            return false;
2✔
306
        } else {
307
            if (type != null) {
2!
308
                buffer[offset++] = (byte) BC_LIST_FIXED;
11✔
309
                writeType(type);
4✔
310
            } else {
311
                buffer[offset++] = (byte) BC_LIST_FIXED_UNTYPED;
×
312
            }
313

314
            writeInt(length);
3✔
315

316
            return false;
2✔
317
        }
318
    }
319

320
    /**
321
     * Writes the tail of the list to the stream for a variable-length list.
322
     */
323
    @Override
324
    public void writeListEnd() throws IOException {
325
        flushIfFull();
×
326

327
        buffer[offset++] = (byte) BC_END;
×
328
    }
×
329

330
    /**
331
     * Writes the map header to the stream.  Map writers will call
332
     * <code>writeMapBegin</code> followed by the map contents and then
333
     * call <code>writeMapEnd</code>.
334
     *<pre>
335
     * <code>
336
     * map ::= M type (value value)* Z
337
     *     ::= H (value value)* Z
338
     * </code>
339
     * </pre>
340
     */
341
    @Override
342
    public void writeMapBegin(String type) throws IOException {
343
        if (SIZE < offset + 32) {
6!
344
            flushBuffer();
×
345
        }
346

347
        if (type != null) {
2✔
348
            buffer[offset++] = BC_MAP;
11✔
349

350
            writeType(type);
4✔
351
        } else {
352
            buffer[offset++] = BC_MAP_UNTYPED;
11✔
353
        }
354
    }
1✔
355

356
    /**
357
     * Writes the tail of the map to the stream.
358
     */
359
    @Override
360
    public void writeMapEnd() throws IOException {
361
        if (SIZE < offset + 32) {
6!
362
            flushBuffer();
×
363
        }
364

365
        buffer[offset++] = (byte) BC_END;
11✔
366
    }
1✔
367

368
    /**
369
     * Writes the object definition
370
     *<pre>
371
     * <code>
372
     * C &lt;string&gt; &lt;int&gt; &lt;string&gt;*
373
     * </code>
374
     * </pre>
375
     * @return the reference number for the class, or -1 if the class is not
376
     */
377
    @Override
378
    public int writeObjectBegin(String type) throws IOException {
379
        int newRef = classRefs.size();
4✔
380
        int ref = classRefs.put(type, newRef, false);
7✔
381

382
        if (SIZE < offset + 32) {
6!
383
            flushBuffer();
×
384
        }
385
        if (newRef != ref) {
3✔
386

387
            if (ref <= OBJECT_DIRECT_MAX) {
3!
388
                buffer[offset++] = (byte) (BC_OBJECT_DIRECT + ref);
15✔
389
            } else {
390
                buffer[offset++] = (byte) 'O';
×
391
                writeInt(ref);
×
392
            }
393

394
            return ref;
2✔
395
        } else {
396

397
            buffer[offset++] = (byte) 'C';
11✔
398

399
            writeString(type);
3✔
400

401
            return -1;
2✔
402
        }
403
    }
404

405
    /**
406
     * Writes the tail of the class definition to the stream.
407
     */
408
    @Override
409
    public void writeClassFieldLength(int len) throws IOException {
410
        writeInt(len);
3✔
411
    }
1✔
412

413
    /**
414
     * Writes the tail of the object definition to the stream.
415
     */
416
    @Override
417
    public void writeObjectEnd() {}
×
418

419
    /**
420
     * <pre>
421
     * <code>
422
     * type ::= string
423
     *      ::= int
424
     * </code>
425
     * </pre>
426
     */
427
    private void writeType(String type) throws IOException {
428
        flushIfFull();
2✔
429

430
        int len = type.length();
3✔
431
        if (len == 0) {
2!
432
            throw new IllegalArgumentException("empty type is not allowed");
×
433
        }
434

435
        if (typeRefs == null) {
3✔
436
            typeRefs = new HashMap<>();
5✔
437
        }
438

439
        Integer typeRefV = typeRefs.get(type);
6✔
440

441
        if (typeRefV != null) {
2✔
442
            int typeRef = typeRefV;
3✔
443

444
            writeInt(typeRef);
3✔
445
        } else {
1✔
446
            typeRefs.put(type, Integer.valueOf(typeRefs.size()));
9✔
447

448
            writeString(type);
3✔
449
        }
450
    }
1✔
451

452
    /**
453
     * Writes a boolean value to the stream.  The boolean will be written
454
     * with the following syntax:
455
     *<pre>
456
     * <code>
457
     * T
458
     * F
459
     * </code>
460
     * </pre>
461
     *
462
     * @param value the boolean value to write.
463
     */
464
    @Override
465
    public void writeBoolean(boolean value) throws IOException {
466
        if (SIZE < offset + 16) {
6!
467
            flushBuffer();
×
468
        }
469

470
        if (value) {
2✔
471
            buffer[offset++] = (byte) 'T';
12✔
472
        } else {
473
            buffer[offset++] = (byte) 'F';
11✔
474
        }
475
    }
1✔
476

477
    /**
478
     * Writes an integer value to the stream.  The integer will be written
479
     * with the following syntax:
480
     *<pre>
481
     * <code>
482
     * I b32 b24 b16 b8
483
     * </code>
484
     * </pre>
485
     *
486
     * @param value the integer value to write.
487
     */
488
    @Override
489
    public void writeInt(int value) throws IOException {
490
        int i = this.offset;
3✔
491

492
        if (SIZE <= i + 16) {
5✔
493
            flushBuffer();
2✔
494
            i = this.offset;
3✔
495
        }
496

497
        if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX) {
6✔
498
            buffer[i++] = (byte) (value + BC_INT_ZERO);
10✔
499
        } else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
6✔
500
            buffer[i++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
11✔
501
            buffer[i++] = (byte) (value);
8✔
502
        } else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
6!
503
            buffer[i++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
11✔
504
            buffer[i++] = (byte) (value >> 8);
9✔
505
            buffer[i++] = (byte) (value);
8✔
506
        } else {
507
            buffer[i++] = (byte) ('I');
6✔
508
            buffer[i++] = (byte) (value >> 24);
9✔
509
            buffer[i++] = (byte) (value >> 16);
9✔
510
            buffer[i++] = (byte) (value >> 8);
9✔
511
            buffer[i++] = (byte) (value);
7✔
512
        }
513

514
        this.offset = i;
3✔
515
    }
1✔
516

517
    /**
518
     * Writes a long value to the stream.  The long will be written
519
     * with the following syntax:
520
     *<pre>
521
     * <code>
522
     * L b64 b56 b48 b40 b32 b24 b16 b8
523
     * </code>
524
     * </pre>
525
     *
526
     * @param value the long value to write.
527
     */
528
    @Override
529
    public void writeLong(long value) throws IOException {
530
        int i = this.offset;
3✔
531

532
        if (SIZE <= i + 16) {
5!
533
            flushBuffer();
×
534
            i = this.offset;
×
535
        }
536

537
        if (LONG_DIRECT_MIN <= value && value <= LONG_DIRECT_MAX) {
8✔
538
            buffer[i++] = (byte) (value + BC_LONG_ZERO);
11✔
539
        } else if (LONG_BYTE_MIN <= value && value <= LONG_BYTE_MAX) {
8!
540
            buffer[i++] = (byte) (BC_LONG_BYTE_ZERO + (value >> 8));
×
541
            buffer[i++] = (byte) (value);
×
542
        } else if (LONG_SHORT_MIN <= value && value <= LONG_SHORT_MAX) {
8!
543
            buffer[i++] = (byte) (BC_LONG_SHORT_ZERO + (value >> 16));
×
544
            buffer[i++] = (byte) (value >> 8);
×
545
            buffer[i++] = (byte) (value);
×
546
        } else if (-0x80000000L <= value && value <= 0x7fffffffL) {
8✔
547
            buffer[i] = (byte) BC_LONG_INT;
5✔
548
            buffer[i + 1] = (byte) (value >> 24);
11✔
549
            buffer[i + 2] = (byte) (value >> 16);
11✔
550
            buffer[i + 3] = (byte) (value >> 8);
11✔
551
            buffer[i + 4] = (byte) (value);
9✔
552

553
            i += 5;
2✔
554
        } else {
555
            buffer[i] = (byte) 'L';
5✔
556
            buffer[i + 1] = (byte) (value >> 56);
11✔
557
            buffer[i + 2] = (byte) (value >> 48);
11✔
558
            buffer[i + 3] = (byte) (value >> 40);
11✔
559
            buffer[i + 4] = (byte) (value >> 32);
11✔
560
            buffer[i + 5] = (byte) (value >> 24);
11✔
561
            buffer[i + 6] = (byte) (value >> 16);
11✔
562
            buffer[i + 7] = (byte) (value >> 8);
11✔
563
            buffer[i + 8] = (byte) (value);
9✔
564

565
            i += 9;
1✔
566
        }
567

568
        this.offset = i;
3✔
569
    }
1✔
570

571
    /**
572
     * Writes a double value to the stream.  The double will be written
573
     * with the following syntax:
574
     * <p>
575
     *     <pre>
576
     * <code>
577
     * D b64 b56 b48 b40 b32 b24 b16 b8
578
     * </code>
579
     * </pre>
580
     *
581
     * @param value the double value to write.
582
     */
583
    @Override
584
    public void writeDouble(double value) throws IOException {
585
        int i = this.offset;
3✔
586

587
        if (SIZE <= i + 16) {
5!
588
            flushBuffer();
×
589
            i = this.offset;
×
590
        }
591

592
        int intValue = (int) value;
3✔
593

594
        if (intValue == value) {
5✔
595
            if (intValue == 0) {
2✔
596
                buffer[i++] = (byte) BC_DOUBLE_ZERO;
6✔
597

598
                this.offset = i;
3✔
599

600
                return;
1✔
601
            } else if (intValue == 1) {
3!
602
                buffer[i++] = (byte) BC_DOUBLE_ONE;
×
603

604
                this.offset = i;
×
605

606
                return;
×
607
            } else if (-0x80 <= intValue && intValue < 0x80) {
6!
608
                buffer[i++] = (byte) BC_DOUBLE_BYTE;
6✔
609
                buffer[i++] = (byte) intValue;
7✔
610

611
                this.offset = i;
3✔
612

613
                return;
1✔
614
            } else if (-0x8000 <= intValue && intValue < 0x8000) {
6!
615
                buffer[i] = (byte) BC_DOUBLE_SHORT;
5✔
616
                buffer[i + 1] = (byte) (intValue >> 8);
10✔
617
                buffer[i + 2] = (byte) intValue;
8✔
618

619
                this.offset = i + 3;
5✔
620

621
                return;
1✔
622
            }
623
        }
624

625
        int mills = (int) (value * 1000);
5✔
626

627
        if (0.001 * mills == value) {
7✔
628
            buffer[i] = (byte) (BC_DOUBLE_MILL);
5✔
629
            buffer[i + 1] = (byte) (mills >> 24);
10✔
630
            buffer[i + 2] = (byte) (mills >> 16);
10✔
631
            buffer[i + 3] = (byte) (mills >> 8);
10✔
632
            buffer[i + 4] = (byte) (mills);
8✔
633

634
            this.offset = i + 5;
5✔
635

636
            return;
1✔
637
        }
638

639
        long bits = Double.doubleToLongBits(value);
3✔
640

641
        buffer[i] = (byte) 'D';
5✔
642
        buffer[i + 1] = (byte) (bits >> 56);
11✔
643
        buffer[i + 2] = (byte) (bits >> 48);
11✔
644
        buffer[i + 3] = (byte) (bits >> 40);
11✔
645
        buffer[i + 4] = (byte) (bits >> 32);
11✔
646
        buffer[i + 5] = (byte) (bits >> 24);
11✔
647
        buffer[i + 6] = (byte) (bits >> 16);
11✔
648
        buffer[i + 7] = (byte) (bits >> 8);
11✔
649
        buffer[i + 8] = (byte) (bits);
9✔
650

651
        this.offset = i + 9;
5✔
652
    }
1✔
653

654
    /**
655
     * Writes a date to the stream.
656
     *<pre>
657
     * <code>
658
     * date ::= d   b7 b6 b5 b4 b3 b2 b1 b0
659
     *      ::= x65 b3 b2 b1 b0
660
     * </code>
661
     * </pre>
662
     *
663
     * @param time the date in milliseconds from the epoch in UTC
664
     */
665
    @Override
666
    public void writeUTCDate(long time) throws IOException {
667
        if (SIZE < offset + 32) {
6!
668
            flushBuffer();
×
669
        }
670

671
        int i = this.offset;
3✔
672

673
        if (time % 60000L == 0) {
6!
674
            // compact date ::= x65 b3 b2 b1 b0
675

676
            long minutes = time / 60000L;
×
677

678
            if ((minutes >> 31) == 0 || (minutes >> 31) == -1) {
×
679
                buffer[i++] = (byte) BC_DATE_MINUTE;
×
680
                buffer[i++] = ((byte) (minutes >> 24));
×
681
                buffer[i++] = ((byte) (minutes >> 16));
×
682
                buffer[i++] = ((byte) (minutes >> 8));
×
683
                buffer[i++] = ((byte) (minutes >> 0));
×
684

685
                this.offset = i;
×
686
                return;
×
687
            }
688
        }
689

690
        buffer[i++] = (byte) BC_DATE;
6✔
691
        buffer[i++] = ((byte) (time >> 56));
10✔
692
        buffer[i++] = ((byte) (time >> 48));
10✔
693
        buffer[i++] = ((byte) (time >> 40));
10✔
694
        buffer[i++] = ((byte) (time >> 32));
10✔
695
        buffer[i++] = ((byte) (time >> 24));
10✔
696
        buffer[i++] = ((byte) (time >> 16));
10✔
697
        buffer[i++] = ((byte) (time >> 8));
10✔
698
        buffer[i++] = ((byte) (time));
8✔
699

700
        this.offset = i;
3✔
701
    }
1✔
702

703
    /**
704
     * Writes a null value to the stream.
705
     * The null will be written with the following syntax
706
     * <pre>
707
     * <code>
708
     * N
709
     * </code>
710
     * </pre>
711
     */
712
    @Override
713
    public void writeNull() throws IOException {
714
        int i = this.offset;
3✔
715

716
        if (SIZE <= i + 16) {
5!
717
            flushBuffer();
×
718
            i = this.offset;
×
719
        }
720

721
        buffer[i++] = 'N';
6✔
722

723
        this.offset = i;
3✔
724
    }
1✔
725

726
    /**
727
     * Writes a string value to the stream using UTF-8 encoding.
728
     * The string will be written with the following syntax:
729
     * <pre>
730
     * <code>
731
     * S b16 b8 string-value
732
     * </code>
733
     * If the value is null, it will be written as
734
     * <code>
735
     * N
736
     * </code>
737
     * </pre>
738
     *
739
     * @param value the string value to write.
740
     */
741
    @Override
742
    public void writeString(String value) throws IOException {
743
        int i = this.offset;
3✔
744

745
        if (SIZE <= i + 16) {
5!
746
            flushBuffer();
×
747
            i = this.offset;
×
748
        }
749

750
        if (value == null) {
2✔
751
            buffer[i++] = (byte) 'N';
6✔
752

753
            this.offset = i;
4✔
754
        } else {
755
            int length = value.length();
3✔
756
            int strOffset = 0;
2✔
757

758
            while (length > 0x8000) {
3!
759
                int sublen = 0x8000;
×
760

761
                i = this.offset;
×
762

763
                if (SIZE <= i + 16) {
×
764
                    flushBuffer();
×
765
                    i = this.offset;
×
766
                }
767

768
                // chunk can't end in high surrogate
769
                char tail = value.charAt(strOffset + sublen - 1);
×
770

771
                if (0xd800 <= tail && tail <= 0xdbff) {
×
772
                    sublen--;
×
773
                }
774

775
                buffer[i] = (byte) BC_STRING_CHUNK;
×
776
                buffer[i + 1] = (byte) (sublen >> 8);
×
777
                buffer[i + 2] = (byte) (sublen);
×
778

779
                this.offset = i + 3;
×
780

781
                printString(value, strOffset, sublen);
×
782

783
                length -= sublen;
×
784
                strOffset += sublen;
×
785
            }
×
786

787
            i = this.offset;
3✔
788

789
            if (SIZE <= i + 16) {
5!
790
                flushBuffer();
×
791
                i = this.offset;
×
792
            }
793

794
            if (length <= STRING_DIRECT_MAX) {
3✔
795
                buffer[i++] = (byte) (BC_STRING_DIRECT + length);
10✔
796
            } else if (length <= STRING_SHORT_MAX) {
3!
797
                buffer[i++] = (byte) (BC_STRING_SHORT + (length >> 8));
11✔
798
                buffer[i++] = (byte) (length);
8✔
799
            } else {
800
                buffer[i++] = (byte) ('S');
×
801
                buffer[i++] = (byte) (length >> 8);
×
802
                buffer[i++] = (byte) (length);
×
803
            }
804

805
            this.offset = i;
3✔
806

807
            printString(value, strOffset, length);
5✔
808
        }
809
    }
1✔
810

811
    /**
812
     * Writes a string value to the stream using UTF-8 encoding.
813
     * The string will be written with the following syntax:
814
     * <pre>
815
     * <code>
816
     * S b16 b8 string-value
817
     * </code>
818
     * If the value is null, it will be written as
819
     * <code>
820
     * N
821
     * </code>
822
     * </pre>
823
     *
824
     */
825
    @Override
826
    public void writeString(char[] buffer, int offset, int length) throws IOException {
827
        if (buffer == null) {
×
828
            if (SIZE < this.offset + 16) {
×
829
                flushBuffer();
×
830
            }
831

832
            this.buffer[this.offset++] = (byte) ('N');
×
833
        } else {
834
            while (length > 0x8000) {
×
835
                int sublen = 0x8000;
×
836

837
                if (SIZE < this.offset + 16) {
×
838
                    flushBuffer();
×
839
                }
840

841
                // chunk can't end in high surrogate
842
                char tail = buffer[offset + sublen - 1];
×
843

844
                if (0xd800 <= tail && tail <= 0xdbff) {
×
845
                    sublen--;
×
846
                }
847

848
                this.buffer[this.offset++] = (byte) BC_STRING_CHUNK;
×
849
                this.buffer[this.offset++] = (byte) (sublen >> 8);
×
850
                this.buffer[this.offset++] = (byte) (sublen);
×
851

852
                printString(buffer, offset, sublen);
×
853

854
                length -= sublen;
×
855
                offset += sublen;
×
856
            }
×
857

858
            if (SIZE < this.offset + 16) {
×
859
                flushBuffer();
×
860
            }
861

862
            if (length <= STRING_DIRECT_MAX) {
×
863
                this.buffer[this.offset++] = (byte) (BC_STRING_DIRECT + length);
×
864
            } else if (length <= STRING_SHORT_MAX) {
×
865
                this.buffer[this.offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
×
866
                this.buffer[this.offset++] = (byte) length;
×
867
            } else {
868
                this.buffer[this.offset++] = (byte) ('S');
×
869
                this.buffer[this.offset++] = (byte) (length >> 8);
×
870
                this.buffer[this.offset++] = (byte) (length);
×
871
            }
872

873
            printString(buffer, offset, length);
×
874
        }
875
    }
×
876

877
    /**
878
     * Writes a byte array to the stream.
879
     * The array will be written with the following syntax:
880
     * <pre>
881
     * <code>
882
     * B b16 b18 bytes
883
     * </code>
884
     * If the value is null, it will be written as
885
     * <code>
886
     * N
887
     * </code>
888
     * </pre>
889
     *
890
     */
891
    @Override
892
    public void writeBytes(byte[] buffer) throws IOException {
893
        if (buffer == null) {
2!
894
            if (SIZE < offset + 16) {
×
895
                flushBuffer();
×
896
            }
897

898
            this.buffer[offset++] = 'N';
×
899
        } else {
900
            writeBytes(buffer, 0, buffer.length);
6✔
901
        }
902
    }
1✔
903

904
    /**
905
     * Writes a byte array to the stream.
906
     * The array will be written with the following syntax:
907
     * <pre>
908
     * <code>
909
     * B b16 b18 bytes
910
     * </code>
911
     * If the value is null, it will be written as
912
     * <code>
913
     * N
914
     * </code>
915
     * </pre>
916
     */
917
    @Override
918
    public void writeBytes(byte[] buffer, int offset, int length) throws IOException {
919
        if (buffer == null) {
2!
920
            if (SIZE < this.offset + 16) {
×
921
                flushBuffer();
×
922
            }
923

924
            this.buffer[this.offset++] = (byte) 'N';
×
925
        } else {
926
            while (SIZE - this.offset - 3 < length) {
8!
927
                int sublen = SIZE - this.offset - 3;
×
928

929
                if (sublen < 16) {
×
930
                    flushBuffer();
×
931

932
                    sublen = SIZE - this.offset - 3;
×
933

934
                    if (length < sublen) {
×
935
                        sublen = length;
×
936
                    }
937
                }
938

939
                this.buffer[this.offset++] = (byte) BC_BINARY_CHUNK;
×
940
                this.buffer[this.offset++] = (byte) (sublen >> 8);
×
941
                this.buffer[this.offset++] = (byte) sublen;
×
942

943
                System.arraycopy(buffer, offset, this.buffer, this.offset, sublen);
×
944
                this.offset += sublen;
×
945

946
                length -= sublen;
×
947
                offset += sublen;
×
948

949
                flushBuffer();
×
950
            }
×
951

952
            if (SIZE < this.offset + 16) {
6!
953
                flushBuffer();
×
954
            }
955

956
            if (length <= BINARY_DIRECT_MAX) {
3✔
957
                this.buffer[this.offset++] = (byte) (BC_BINARY_DIRECT + length);
15✔
958
            } else if (length <= BINARY_SHORT_MAX) {
3!
959
                this.buffer[this.offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
16✔
960
                this.buffer[this.offset++] = (byte) (length);
13✔
961
            } else {
962
                this.buffer[this.offset++] = (byte) 'B';
×
963
                this.buffer[this.offset++] = (byte) (length >> 8);
×
964
                this.buffer[this.offset++] = (byte) (length);
×
965
            }
966

967
            System.arraycopy(buffer, offset, this.buffer, this.offset, length);
8✔
968

969
            this.offset += length;
6✔
970
        }
971
    }
1✔
972

973
    /**
974
     * Writes a byte buffer to the stream.
975
     */
976
    @Override
977
    public void writeByteBufferStart() {}
×
978

979
    /**
980
     * Writes a byte buffer to the stream.
981
     * <pre>
982
     * <code>
983
     * b b16 b18 bytes
984
     * </code>
985
     * </pre>
986
     */
987
    @Override
988
    public void writeByteBufferPart(byte[] buffer, int offset, int length) throws IOException {
989
        while (length > 0) {
×
990
            flushIfFull();
×
991

992
            int sublen = this.buffer.length - this.offset;
×
993

994
            if (length < sublen) {
×
995
                sublen = length;
×
996
            }
997

998
            this.buffer[this.offset++] = BC_BINARY_CHUNK;
×
999
            this.buffer[this.offset++] = (byte) (sublen >> 8);
×
1000
            this.buffer[this.offset++] = (byte) sublen;
×
1001

1002
            System.arraycopy(buffer, offset, this.buffer, this.offset, sublen);
×
1003

1004
            this.offset += sublen;
×
1005
            length -= sublen;
×
1006
            offset += sublen;
×
1007
        }
×
1008
    }
×
1009

1010
    /**
1011
     * Writes a byte buffer to the stream.
1012
     * <pre>
1013
     * <code>
1014
     * b b16 b18 bytes
1015
     * </code>
1016
     * </pre>
1017
     */
1018
    @Override
1019
    public void writeByteBufferEnd(byte[] buffer, int offset, int length) throws IOException {
1020
        writeBytes(buffer, offset, length);
×
1021
    }
×
1022

1023
    /**
1024
     * Returns an output stream to write binary data.
1025
     */
1026
    public OutputStream getBytesOutputStream() throws IOException {
1027
        return new BytesOutputStream();
×
1028
    }
1029

1030
    /**
1031
     * Writes a full output stream.
1032
     */
1033
    @Override
1034
    public void writeByteStream(InputStream is) throws IOException {
1035
        while (true) {
1036
            int len = SIZE - offset - 3;
×
1037

1038
            if (len < 16) {
×
1039
                flushBuffer();
×
1040
                len = SIZE - offset - 3;
×
1041
            }
1042

1043
            len = is.read(buffer, offset + 3, len);
×
1044

1045
            if (len <= 0) {
×
1046
                buffer[offset++] = BC_BINARY_DIRECT;
×
1047
                return;
×
1048
            }
1049

1050
            buffer[offset] = (byte) BC_BINARY_CHUNK;
×
1051
            buffer[offset + 1] = (byte) (len >> 8);
×
1052
            buffer[offset + 2] = (byte) (len);
×
1053

1054
            offset += len + 3;
×
1055
        }
×
1056
    }
1057

1058
    /**
1059
     * Writes a reference.
1060
     * <pre>
1061
     * x51 &lt;int&gt;
1062
     * </pre>
1063
     *
1064
     * @param value the integer value to write.
1065
     */
1066
    @Override
1067
    protected void writeRef(int value) throws IOException {
1068
        if (SIZE < offset + 16) {
6!
1069
            flushBuffer();
×
1070
        }
1071

1072
        buffer[offset++] = (byte) BC_REF;
11✔
1073

1074
        writeInt(value);
3✔
1075
    }
1✔
1076

1077
    /**
1078
     * If the object has already been written, just write its ref.
1079
     *
1080
     * @return true if we're writing a ref.
1081
     */
1082
    @Override
1083
    public boolean addRef(Object object) throws IOException {
1084
        if (isUnshared) {
3!
1085
            refCount++;
×
1086
            return false;
×
1087
        }
1088

1089
        int newRef = refCount;
3✔
1090

1091
        int ref = addRef(object, newRef, false);
6✔
1092

1093
        if (ref != newRef) {
3✔
1094
            writeRef(ref);
3✔
1095

1096
            return true;
2✔
1097
        } else {
1098
            refCount++;
6✔
1099

1100
            return false;
2✔
1101
        }
1102
    }
1103

1104
    @Override
1105
    public int getRef(Object obj) {
1106
        if (isUnshared) {
3!
1107
            return -1;
×
1108
        }
1109

1110
        return refs.get(obj);
5✔
1111
    }
1112

1113
    /**
1114
     * Removes a reference.
1115
     */
1116
    public boolean removeRef(Object obj) {
1117
        if (isUnshared) {
×
1118
            return false;
×
1119
        } else {
1120
            refs.remove(obj);
×
1121

1122
            return true;
×
1123
        }
1124
    }
1125

1126
    /**
1127
     * Replaces a reference from one object to another.
1128
     */
1129
    @Override
1130
    public boolean replaceRef(Object oldRef, Object newRef) {
1131
        if (isUnshared) {
3!
1132
            return false;
×
1133
        }
1134

1135
        int value = refs.get(oldRef);
5✔
1136

1137
        if (value >= 0) {
2!
1138
            addRef(newRef, value, true);
6✔
1139

1140
            refs.remove(oldRef);
4✔
1141

1142
            return true;
2✔
1143
        } else {
1144
            return false;
×
1145
        }
1146
    }
1147

1148
    private int addRef(Object value, int newRef, boolean isReplace) {
1149

1150
        return refs.put(value, newRef, isReplace);
7✔
1151
    }
1152

1153
    /**
1154
     * Starts the streaming message
1155
     *
1156
     * <p>A streaming message starts with 'P'</p>
1157
     *
1158
     * <pre>
1159
     * P x02 x00
1160
     * </pre>
1161
     */
1162
    public void writeStreamingObject(Object obj) throws IOException {
1163
        startPacket();
×
1164

1165
        writeObject(obj);
×
1166

1167
        endPacket();
×
1168
    }
×
1169

1170
    /**
1171
     * Starts a streaming packet
1172
     *
1173
     * <p>A streaming contains a set of chunks, ending with a zero chunk.
1174
     * Each chunk is a length followed by data where the length is
1175
     * encoded by (b1xxxxxxxx)* b0xxxxxxxx</p>
1176
     */
1177
    public void startPacket() throws IOException {
1178
        refs.clear();
×
1179
        refCount = 0;
×
1180

1181
        flushBuffer();
×
1182

1183
        isPacket = true;
×
1184
        offset = 4;
×
1185
        // 0x05 = binary
1186
        buffer[0] = (byte) 0x05;
×
1187
        buffer[1] = (byte) 0x55;
×
1188
        buffer[2] = (byte) 0x55;
×
1189
        buffer[3] = (byte) 0x55;
×
1190
    }
×
1191

1192
    public void endPacket() throws IOException {
1193
        int i = this.offset;
×
1194

1195
        if (os == null) {
×
1196
            this.offset = 0;
×
1197
            return;
×
1198
        }
1199

1200
        int len = i - 4;
×
1201

1202
        if (len < 0x7e) {
×
1203
            buffer[2] = buffer[0];
×
1204
        } else {
1205
            buffer[1] = (byte) (0x7e);
×
1206
            buffer[2] = (byte) (len >> 8);
×
1207
        }
1208
        buffer[3] = (byte) (len);
×
1209

1210
        isPacket = false;
×
1211
        this.offset = 0;
×
1212

1213
        if (len < 0x7e) {
×
1214
            os.write(buffer, 2, i - 2);
×
1215
        } else {
1216
            os.write(buffer, 0, i);
×
1217
        }
1218
    }
×
1219

1220
    /**
1221
     * Prints a string to the stream, encoded as UTF-8 with preceeding length
1222
     *
1223
     * @param v the string to print.
1224
     */
1225
    public void printLenString(String v) throws IOException {
1226
        if (SIZE < offset + 16) {
×
1227
            flushBuffer();
×
1228
        }
1229

1230
        if (v == null) {
×
1231
            buffer[offset++] = (byte) (0);
×
1232
            buffer[offset++] = (byte) (0);
×
1233
        } else {
1234
            int len = v.length();
×
1235
            buffer[offset++] = (byte) (len >> 8);
×
1236
            buffer[offset++] = (byte) (len);
×
1237

1238
            printString(v, 0, len);
×
1239
        }
1240
    }
×
1241

1242
    /**
1243
     * Prints a string to the stream, encoded as UTF-8
1244
     *
1245
     * @param v the string to print.
1246
     */
1247
    public void printString(String v) throws IOException {
1248
        printString(v, 0, v.length());
×
1249
    }
×
1250

1251
    /**
1252
     * Prints a string to the stream, encoded as UTF-8
1253
     *
1254
     * @param v the string to print.
1255
     */
1256
    public void printString(String v, int strOffset, int length) throws IOException {
1257
        int ioffset = this.offset;
3✔
1258

1259
        for (int i = 0; i < length; i++) {
7✔
1260
            if (SIZE <= ioffset + 16) {
5✔
1261
                this.offset = ioffset;
3✔
1262
                flushBuffer();
2✔
1263
                ioffset = this.offset;
3✔
1264
            }
1265

1266
            char ch = v.charAt(i + strOffset);
6✔
1267

1268
            if (ch < 0x80) {
3✔
1269
                buffer[ioffset++] = (byte) (ch);
8✔
1270
            } else if (ch < 0x800) {
3!
1271
                buffer[ioffset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
×
1272
                buffer[ioffset++] = (byte) (0x80 + (ch & 0x3f));
×
1273
            } else {
1274
                buffer[ioffset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
13✔
1275
                buffer[ioffset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
13✔
1276
                buffer[ioffset++] = (byte) (0x80 + (ch & 0x3f));
11✔
1277
            }
1278
        }
1279

1280
        this.offset = ioffset;
3✔
1281
    }
1✔
1282

1283
    /**
1284
     * Prints a string to the stream, encoded as UTF-8
1285
     *
1286
     * @param v the string to print.
1287
     */
1288
    public void printString(char[] v, int strOffset, int length) throws IOException {
1289
        int ioffset = this.offset;
×
1290

1291
        for (int i = 0; i < length; i++) {
×
1292
            if (SIZE <= ioffset + 16) {
×
1293
                this.offset = ioffset;
×
1294
                flushBuffer();
×
1295
                ioffset = this.offset;
×
1296
            }
1297

1298
            char ch = v[i + strOffset];
×
1299

1300
            if (ch < 0x80) {
×
1301
                buffer[ioffset++] = (byte) (ch);
×
1302
            } else if (ch < 0x800) {
×
1303
                buffer[ioffset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
×
1304
                buffer[ioffset++] = (byte) (0x80 + (ch & 0x3f));
×
1305
            } else {
1306
                buffer[ioffset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
×
1307
                buffer[ioffset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
×
1308
                buffer[ioffset++] = (byte) (0x80 + (ch & 0x3f));
×
1309
            }
1310
        }
1311

1312
        this.offset = ioffset;
×
1313
    }
×
1314

1315
    protected final void flushIfFull() throws IOException {
1316

1317
        if (SIZE < offset + 32) {
6!
1318
            flushBuffer();
×
1319
        }
1320
    }
1✔
1321

1322
    @Override
1323
    public final void flush() throws IOException {
1324
        flushBuffer();
2✔
1325

1326
        if (os != null) {
3!
1327
            os.flush();
3✔
1328
        }
1329
    }
1✔
1330

1331
    public final void flushBuffer() throws IOException {
1332
        int ioffset = this.offset;
3✔
1333

1334
        if (!isPacket && ioffset > 0) {
5!
1335
            this.offset = 0;
3✔
1336
            if (os != null) {
3!
1337
                os.write(buffer, 0, ioffset);
8✔
1338
            }
1339
        } else if (isPacket && ioffset > 4) {
3!
1340
            int len = ioffset - 4;
×
1341

1342
            buffer[0] |= (byte) 0x80;
×
1343
            buffer[1] = (byte) (0x7e);
×
1344
            buffer[2] = (byte) (len >> 8);
×
1345
            buffer[3] = (byte) (len);
×
1346
            this.offset = 4;
×
1347

1348
            if (os != null) {
×
1349
                os.write(buffer, 0, ioffset);
×
1350
            }
1351

1352
            buffer[0] = (byte) 0x00;
×
1353
            buffer[1] = (byte) 0x56;
×
1354
            buffer[2] = (byte) 0x56;
×
1355
            buffer[3] = (byte) 0x56;
×
1356
        }
1357
    }
1✔
1358

1359
    @Override
1360
    public void close() throws IOException {
1361
        // hessian/3a8c
1362
        flush();
2✔
1363

1364
        OutputStream los = this.os;
3✔
1365
        this.os = null;
3✔
1366

1367
        if (los != null && isCloseStreamOnClose) {
5!
1368
            los.close();
×
1369
        }
1370
    }
1✔
1371

1372
    public void free() {
1373
        reset();
2✔
1374

1375
        os = null;
3✔
1376
        isCloseStreamOnClose = false;
3✔
1377
    }
1✔
1378

1379
    /**
1380
     * Resets the references for streaming.
1381
     */
1382
    @Override
1383
    public void resetReferences() {
1384
        refs.clear();
×
1385
        refCount = 0;
×
1386
    }
×
1387

1388
    /**
1389
     * Resets all counters and references
1390
     */
1391
    public void reset() {
1392
        refs.clear();
3✔
1393
        refCount = 0;
3✔
1394

1395
        classRefs.clear();
3✔
1396
        typeRefs = null;
3✔
1397
        offset = 0;
3✔
1398
        isPacket = false;
3✔
1399
        isUnshared = false;
3✔
1400
    }
1✔
1401

1402
    class BytesOutputStream extends OutputStream {
1403
        private int startOffset;
1404

1405
        BytesOutputStream() throws IOException {
×
1406
            if (SIZE < offset + 16) {
×
1407
                HessianEncoder.this.flushBuffer();
×
1408
            }
1409

1410
            startOffset = offset;
×
1411
            offset += 3; // skip 'b' xNN xNN
×
1412
        }
×
1413

1414
        @Override
1415
        public void write(int ch) throws IOException {
1416
            if (SIZE <= offset) {
×
1417
                int length = (offset - startOffset) - 3;
×
1418

1419
                buffer[startOffset] = (byte) BC_BINARY_CHUNK;
×
1420
                buffer[startOffset + 1] = (byte) (length >> 8);
×
1421
                buffer[startOffset + 2] = (byte) (length);
×
1422

1423
                HessianEncoder.this.flushBuffer();
×
1424

1425
                startOffset = offset;
×
1426
                offset += 3;
×
1427
            }
1428

1429
            buffer[offset++] = (byte) ch;
×
1430
        }
×
1431

1432
        @Override
1433
        public void write(byte[] buffer, int offset, int length) throws IOException {
1434
            while (length > 0) {
×
1435
                int sublen = SIZE - HessianEncoder.this.offset;
×
1436

1437
                if (length < sublen) {
×
1438
                    sublen = length;
×
1439
                }
1440

1441
                if (sublen > 0) {
×
1442
                    System.arraycopy(buffer, offset, HessianEncoder.this.buffer, HessianEncoder.this.offset, sublen);
×
1443
                    HessianEncoder.this.offset += sublen;
×
1444
                }
1445

1446
                length -= sublen;
×
1447
                offset += sublen;
×
1448

1449
                if (SIZE <= HessianEncoder.this.offset) {
×
1450
                    int chunkLength = (HessianEncoder.this.offset - startOffset) - 3;
×
1451

1452
                    HessianEncoder.this.buffer[startOffset] = (byte) BC_BINARY_CHUNK;
×
1453
                    HessianEncoder.this.buffer[startOffset + 1] = (byte) (chunkLength >> 8);
×
1454
                    HessianEncoder.this.buffer[startOffset + 2] = (byte) (chunkLength);
×
1455

1456
                    HessianEncoder.this.flushBuffer();
×
1457

1458
                    startOffset = HessianEncoder.this.offset;
×
1459
                    HessianEncoder.this.offset += 3;
×
1460
                }
1461
            }
×
1462
        }
×
1463

1464
        @Override
1465
        public void close() throws IOException {
1466
            int i = this.startOffset;
×
1467
            this.startOffset = -1;
×
1468

1469
            if (i < 0) {
×
1470
                return;
×
1471
            }
1472

1473
            int length = (offset - i) - 3;
×
1474

1475
            buffer[i] = (byte) 'B';
×
1476
            buffer[i + 1] = (byte) (length >> 8);
×
1477
            buffer[i + 2] = (byte) (length);
×
1478

1479
            HessianEncoder.this.flushBuffer();
×
1480
        }
×
1481
    }
1482
}
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