1 package com.fasterxml.jackson.dataformat.cbor;
2
3 import java.util.Arrays;
4 import java.io.*;
5 import java.math.BigDecimal;
6 import java.math.BigInteger;
7
8 import com.fasterxml.jackson.core.*;
9 import com.fasterxml.jackson.core.base.GeneratorBase;
10 import com.fasterxml.jackson.core.io.IOContext;
11 import com.fasterxml.jackson.core.json.DupDetector;
12
13 import static com.fasterxml.jackson.dataformat.cbor.CBORConstants.*;
14
15 /**
16  * {@link JsonGenerator} implementation that writes CBOR encoded content.
17  *
18  * @author Tatu Saloranta
19  */

20 public class CBORGenerator extends GeneratorBase
21 {
22     private final static int[] NO_INTS = new int[0];
23
24     /**
25      * Let's ensure that we have big enough output buffer because of safety
26      * margins we need for UTF-8 encoding.
27      */

28     final static int BYTE_BUFFER_FOR_OUTPUT = 16000;
29
30     /**
31      * Longest char chunk we will output is chosen so that it is guaranteed to
32      * fit in an empty buffer even if everything encoded in 3-byte sequences;
33      * but also fit two full chunks in case of single-byte (ascii) output.
34      */

35     private final static int MAX_LONG_STRING_CHARS = (BYTE_BUFFER_FOR_OUTPUT / 4) - 4;
36
37     /**
38      * This is the worst case length (in bytes) of maximum chunk we ever write.
39      */

40     private final static int MAX_LONG_STRING_BYTES = (MAX_LONG_STRING_CHARS * 3) + 3;
41
42     /**
43      * Enumeration that defines all togglable features for CBOR generator.
44      */

45     public enum Feature implements FormatFeature {
46         /**
47          * Feature that determines whether generator should try to use smallest
48          * (size-wise) integer representation: if true, will use smallest
49          * representation that is enough to retain value; if false, will use
50          * length indicated by argument type (4-byte for <code>int</code>,
51          * 8-byte for <code>long</code> and so on).
52          */

53         WRITE_MINIMAL_INTS(true),
54
55         /**
56          * Feature that determines whether CBOR "Self-Describe Tag" (value
57          * 55799, encoded as 3-byte sequence of <code>0xD9, 0xD9, 0xF7</code>)
58          * should be written at the beginning of document or not.
59          * <p>
60          * Default value is <code>false</code> meaning that type tag will not be
61          * written at the beginning of a new document.
62          *
63          * @since 2.5
64          */

65         WRITE_TYPE_HEADER(false), ;
66
67         protected final boolean _defaultState;
68         protected final int _mask;
69
70         /**
71          * Method that calculates bit set (flags) of all features that are
72          * enabled by default.
73          */

74         public static int collectDefaults() {
75             int flags = 0;
76             for (Feature f : values()) {
77                 if (f.enabledByDefault()) {
78                     flags |= f.getMask();
79                 }
80             }
81             return flags;
82         }
83
84         private Feature(boolean defaultState) {
85             _defaultState = defaultState;
86             _mask = (1 << ordinal());
87         }
88
89         @Override
90         public boolean enabledByDefault() {
91             return _defaultState;
92         }
93
94         @Override
95         public boolean enabledIn(int flags) {
96             return (flags & getMask()) != 0;
97         }
98
99         @Override
100         public int getMask() {
101             return _mask;
102         }
103     }
104
105     /**
106      * To simplify certain operations, we require output buffer length to allow
107      * outputting of contiguous 256 character UTF-8 encoded String value. Length
108      * of the longest UTF-8 code point (from Java char) is 3 bytes, and we need
109      * both initial token byte and single-byte end marker so we get following
110      * value.
111      * <p>
112      * Note: actually we could live with shorter one; absolute minimum would be
113      * for encoding 64-character Strings.
114      */

115     private final static int MIN_BUFFER_LENGTH = (3 * 256) + 2;
116
117     /**
118      * Special value that is use to keep tracks of arrays and maps opened with infinite length
119      */

120     private final static int INDEFINITE_LENGTH = -2; // just to allow -1 as marker for "one too many"
121     
122     /*
123     /**********************************************************
124     /* Configuration
125     /**********************************************************
126      */

127
128     final protected IOContext _ioContext;
129
130     final protected OutputStream _out;
131
132     /**
133      * Bit flag composed of bits that indicate which
134      * {@link CBORGenerator.Feature}s are enabled.
135      */

136     protected int _formatFeatures;
137
138     protected boolean _cfgMinimalInts;
139
140     /*
141     /**********************************************************
142     /* Output state
143     /**********************************************************
144      */

145
146     /**
147      * @since 2.10
148      */

149     protected CBORWriteContext _cborContext;
150     
151     /*
152     /**********************************************************
153     /* Output buffering
154     /**********************************************************
155      */

156
157     /**
158      * Intermediate buffer in which contents are buffered before being written
159      * using {@link #_out}.
160      */

161     protected byte[] _outputBuffer;
162
163     /**
164      * Pointer to the next available byte in {@link #_outputBuffer}
165      */

166     protected int _outputTail = 0;
167
168     /**
169      * Offset to index after the last valid index in {@link #_outputBuffer}.
170      * Typically same as length of the buffer.
171      */

172     protected final int _outputEnd;
173
174     /**
175      * Intermediate buffer in which characters of a String are copied before
176      * being encoded.
177      */

178     protected char[] _charBuffer;
179
180     protected final int _charBufferLength;
181
182     /**
183      * Let's keep track of how many bytes have been output, may prove useful
184      * when debugging. This does <b>not</b> include bytes buffered in the output
185      * buffer, just bytes that have been written using underlying stream writer.
186      */

187     protected int _bytesWritten;
188
189     /*
190     /**********************************************************
191     /* Tracking of remaining elements to write
192     /**********************************************************
193      */

194
195     protected int[] _elementCounts = NO_INTS;
196
197     protected int _elementCountsPtr;
198
199     /**
200      * Number of elements remaining in the current complex structure (if any),
201      * when writing defined-length Arrays, Objects; marker {@link #INDEFINITE_LENGTH}
202      * otherwise.
203      */

204     protected int _currentRemainingElements = INDEFINITE_LENGTH;
205
206     /*
207     /**********************************************************
208     /* Shared String detection
209     /**********************************************************
210      */

211
212     /**
213      * Flag that indicates whether the output buffer is recycable (and needs to
214      * be returned to recycler once we are done) or not.
215      */

216     protected boolean _bufferRecyclable;
217
218     /*
219     /**********************************************************
220     /* Life-cycle
221     /**********************************************************
222      */

223
224     public CBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures,
225             ObjectCodec codec, OutputStream out) {
226         super(stdFeatures, codec, /* Write Context */ null);
227         DupDetector dups = JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION.enabledIn(stdFeatures)
228                 ? DupDetector.rootDetector(this)
229                 : null;
230         // NOTE: we passed `nullfor default write context
231         _cborContext = CBORWriteContext.createRootContext(dups);
232         _formatFeatures = formatFeatures;
233         _cfgMinimalInts = Feature.WRITE_MINIMAL_INTS.enabledIn(formatFeatures);
234         _ioContext = ctxt;
235         _out = out;
236         _bufferRecyclable = true;
237         _outputBuffer = ctxt.allocWriteEncodingBuffer(BYTE_BUFFER_FOR_OUTPUT);
238         _outputEnd = _outputBuffer.length;
239         _charBuffer = ctxt.allocConcatBuffer();
240         _charBufferLength = _charBuffer.length;
241         // let's just sanity check to prevent nasty odd errors
242         if (_outputEnd < MIN_BUFFER_LENGTH) {
243             throw new IllegalStateException("Internal encoding buffer length ("
244                     + _outputEnd + ") too short, must be at least "
245                     + MIN_BUFFER_LENGTH);
246         }
247     }
248
249     /**
250      * Alternative constructor that may be used to feed partially initialized content.
251      * 
252      * @param outputBuffer
253      *            Buffer to use for output before flushing to the underlying stream
254      * @param offset
255      *            Offset pointing past already buffered content; that is, number
256      *            of bytes of valid content to output, within buffer.
257      */

258     public CBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures,
259             ObjectCodec codec, OutputStream out, byte[] outputBuffer,
260             int offset, boolean bufferRecyclable) {
261         super(stdFeatures, codec, /* Write Context */ null);
262         DupDetector dups = JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION.enabledIn(stdFeatures)
263                 ? DupDetector.rootDetector(this)
264                 : null;
265         // NOTE: we passed `nullfor default write context
266         _cborContext = CBORWriteContext.createRootContext(dups);
267         _formatFeatures = formatFeatures;
268         _cfgMinimalInts = Feature.WRITE_MINIMAL_INTS.enabledIn(formatFeatures);
269         _ioContext = ctxt;
270         _out = out;
271         _bufferRecyclable = bufferRecyclable;
272         _outputTail = offset;
273         _outputBuffer = outputBuffer;
274         _outputEnd = _outputBuffer.length;
275         _charBuffer = ctxt.allocConcatBuffer();
276         _charBufferLength = _charBuffer.length;
277         // let's just sanity check to prevent nasty odd errors
278         if (_outputEnd < MIN_BUFFER_LENGTH) {
279             throw new IllegalStateException("Internal encoding buffer length ("
280                     + _outputEnd + ") too short, must be at least "
281                     + MIN_BUFFER_LENGTH);
282         }
283     }
284
285     /*
286     /**********************************************************
287     /* Versioned
288     /**********************************************************
289      */

290
291     @Override
292     public Version version() {
293         return PackageVersion.VERSION;
294     }
295
296     /*
297     /**********************************************************
298     /* Capability introspection
299     /**********************************************************
300      */

301
302     @Override
303     public boolean canWriteBinaryNatively() {
304         return true;
305     }
306
307     /*
308     /**********************************************************
309     /* Overridden methods, configuration
310     /**********************************************************
311      */

312
313     /**
314      * No way (or need) to indent anything, so let's block any attempts. (should
315      * we throw an exception instead?)
316      */

317     @Override
318     public JsonGenerator useDefaultPrettyPrinter() {
319         return this;
320     }
321
322     /**
323      * No way (or need) to indent anything, so let's block any attempts. (should
324      * we throw an exception instead?)
325      */

326     @Override
327     public JsonGenerator setPrettyPrinter(PrettyPrinter pp) {
328         return this;
329     }
330
331     @Override
332     public Object getOutputTarget() {
333         return _out;
334     }
335
336     @Override
337     public int getOutputBuffered() {
338         return _outputTail;
339     }
340
341     // public JsonParser overrideStdFeatures(int values, int mask)
342
343     @Override
344     public int getFormatFeatures() {
345         return _formatFeatures;
346     }
347
348     @Override
349     public JsonGenerator overrideStdFeatures(int values, int mask) {
350         int oldState = _features;
351         int newState = (oldState & ~mask) | (values & mask);
352         if (oldState != newState) {
353             _features = newState;
354         }
355         return this;
356     }
357
358     @Override
359     public JsonGenerator overrideFormatFeatures(int values, int mask) {
360         int oldState = _formatFeatures;
361         int newState = (_formatFeatures & ~mask) | (values & mask);
362         if (oldState != newState) {
363             _formatFeatures = newState;
364             _cfgMinimalInts = Feature.WRITE_MINIMAL_INTS.enabledIn(newState);
365         }
366         return this;
367     }
368
369     /*
370     /**********************************************************
371     /* Overridden methods, output context (and related)
372     /**********************************************************
373      */

374
375     @Override
376     public Object getCurrentValue() {
377         return _cborContext.getCurrentValue();
378     }
379
380     @Override
381     public void setCurrentValue(Object v) {
382         _cborContext.setCurrentValue(v);
383     }
384
385     @Override
386     public JsonStreamContext getOutputContext() {
387         return _cborContext;
388     }
389
390     /*
391     /**********************************************************
392     /* Extended API, configuration
393     /**********************************************************
394      */

395
396     public CBORGenerator enable(Feature f) {
397         _formatFeatures |= f.getMask();
398         if (f == Feature.WRITE_MINIMAL_INTS) {
399             _cfgMinimalInts = true;
400         }
401         return this;
402     }
403
404     public CBORGenerator disable(Feature f) {
405         _formatFeatures &= ~f.getMask();
406         if (f == Feature.WRITE_MINIMAL_INTS) {
407             _cfgMinimalInts = false;
408         }
409         return this;
410     }
411
412     public final boolean isEnabled(Feature f) {
413         return (_formatFeatures & f.getMask()) != 0;
414     }
415
416     public CBORGenerator configure(Feature f, boolean state) {
417         if (state) {
418             enable(f);
419         } else {
420             disable(f);
421         }
422         return this;
423     }
424
425     /*
426     /**********************************************************
427     /* Overridden methods, write methods
428     /**********************************************************
429      */

430
431     /*
432      * And then methods overridden to make final, streamline some aspects...
433      */

434
435     @Override
436     public final void writeFieldName(String name) throws IOException {
437         if (!_cborContext.writeFieldName(name)) {
438             _reportError("Can not write a field name, expecting a value");
439         }
440         _writeString(name);
441     }
442
443     @Override
444     public final void writeFieldName(SerializableString name)
445             throws IOException {
446         // Object is a value, need to verify it's allowed
447         if (!_cborContext.writeFieldName(name.getValue())) {
448             _reportError("Can not write a field name, expecting a value");
449         }
450         byte[] raw = name.asUnquotedUTF8();
451         final int len = raw.length;
452         if (len == 0) {
453             _writeByte(BYTE_EMPTY_STRING);
454             return;
455         }
456         _writeLengthMarker(PREFIX_TYPE_TEXT, len);
457         _writeBytes(raw, 0, len);
458     }
459
460     @Override // since 2.8
461     public final void writeFieldId(long id) throws IOException {
462         if (!_cborContext.writeFieldId(id)) {
463             _reportError("Can not write a field id, expecting a value");
464         }
465         _writeLongNoCheck(id);
466     }
467
468     /*
469     /**********************************************************
470     /* Overridden methods, copying with tag-awareness
471     /**********************************************************
472      */

473
474     /**
475      * Specialize {@link JsonGenerator#copyCurrentEvent} to handle tags.
476      */

477     @Override
478     public void copyCurrentEvent(JsonParser p) throws IOException {
479         maybeCopyTag(p);
480         super.copyCurrentEvent(p);
481     }
482
483     /**
484      * Specialize {@link JsonGenerator#copyCurrentStructure} to handle tags.
485      */

486     @Override
487     public void copyCurrentStructure(JsonParser p) throws IOException {
488         maybeCopyTag(p);
489         super.copyCurrentStructure(p);
490     }
491
492     protected void maybeCopyTag(JsonParser p) throws IOException {
493         if (p instanceof CBORParser) {
494             if (p.hasCurrentToken()) {
495                 final int currentTag = ((CBORParser) p).getCurrentTag();
496
497                 if (currentTag != -1) {
498                     writeTag(currentTag);
499                 }
500             }
501         }
502     }
503
504     /*
505     /**********************************************************
506     /* Output method implementations, structural
507     /**********************************************************
508      */

509
510     @Override
511     public final void writeStartArray() throws IOException {
512         _verifyValueWrite("start an array");
513         _cborContext = _cborContext.createChildArrayContext(null);
514         if (_elementCountsPtr > 0) {
515             _pushRemainingElements();
516         }
517         _currentRemainingElements = INDEFINITE_LENGTH;
518         _writeByte(BYTE_ARRAY_INDEFINITE);
519     }
520
521     /*
522      * Unlike with JSON, this method is using slightly optimized version since
523      * CBOR has a variant that allows embedding length in array start marker.
524      */

525      
526     @Override
527     public void writeStartArray(int elementsToWrite) throws IOException {
528         _verifyValueWrite("start an array");
529         _cborContext = _cborContext.createChildArrayContext(null);
530         _pushRemainingElements();
531         _currentRemainingElements = elementsToWrite;
532         _writeLengthMarker(PREFIX_TYPE_ARRAY, elementsToWrite);
533     }
534
535     @Override
536     public final void writeEndArray() throws IOException {
537         if (!_cborContext.inArray()) {
538             _reportError("Current context not Array but "+_cborContext.typeDesc());
539         }
540         closeComplexElement();
541         _cborContext = _cborContext.getParent();
542     }
543
544     @Override
545     public final void writeStartObject() throws IOException {
546         _verifyValueWrite("start an object");
547         _cborContext = _cborContext.createChildObjectContext(null);
548         if (_elementCountsPtr > 0) {
549             _pushRemainingElements();
550         }
551         _currentRemainingElements = INDEFINITE_LENGTH;
552         _writeByte(BYTE_OBJECT_INDEFINITE);
553     }
554
555     @Override
556     // since 2.8
557     public final void writeStartObject(Object forValue) throws IOException {
558         _verifyValueWrite("start an object");
559         CBORWriteContext ctxt = _cborContext.createChildObjectContext(forValue);
560         _cborContext = ctxt;
561         if (_elementCountsPtr > 0) {
562             _pushRemainingElements();
563         }
564         _currentRemainingElements = INDEFINITE_LENGTH;
565         _writeByte(BYTE_OBJECT_INDEFINITE);
566     }
567
568     public final void writeStartObject(int elementsToWrite) throws IOException {
569         _verifyValueWrite("start an object");
570         _cborContext = _cborContext.createChildObjectContext(null);
571         _pushRemainingElements();
572         _currentRemainingElements = elementsToWrite;
573         _writeLengthMarker(PREFIX_TYPE_OBJECT, elementsToWrite);
574     }
575
576     @Override
577     public final void writeEndObject() throws IOException {
578         if (!_cborContext.inObject()) {
579             _reportError("Current context not Object but "+ _cborContext.typeDesc());
580         }
581         closeComplexElement();
582         _cborContext = _cborContext.getParent();
583     }
584
585     @Override // since 2.8
586     public void writeArray(int[] array, int offset, int length) throws IOException
587     {
588         _verifyOffsets(array.length, offset, length);
589         // short-cut, do not create child array context etc
590         _verifyValueWrite("write int array");
591         _writeLengthMarker(PREFIX_TYPE_ARRAY, length);
592
593         if (_cfgMinimalInts) {
594             for (int i = offset, end = offset+length; i < end; ++i) {
595                 final int value = array[i];
596                 if (value < 0) {
597                     _writeIntMinimal(PREFIX_TYPE_INT_NEG, -value - 1);
598                 } else {
599                     _writeIntMinimal(PREFIX_TYPE_INT_POS, value);
600                 }
601             }
602         } else {
603             for (int i = offset, end = offset+length; i < end; ++i) {
604                 final int value = array[i];
605                 if (value < 0) {
606                     _writeIntFull(PREFIX_TYPE_INT_NEG, -value - 1);
607                 } else {
608                     _writeIntFull(PREFIX_TYPE_INT_POS, value);
609                 }
610             }
611         }
612     }
613
614     @Override // since 2.8
615     public void writeArray(long[] array, int offset, int length) throws IOException
616     {
617         _verifyOffsets(array.length, offset, length);
618         // short-cut, do not create child array context etc
619         _verifyValueWrite("write int array");
620         _writeLengthMarker(PREFIX_TYPE_ARRAY, length);
621         for (int i = offset, end = offset+length; i < end; ++i) {
622             _writeLongNoCheck(array[i]);
623         }
624     }
625
626     @Override // since 2.8
627     public void writeArray(double[] array, int offset, int length) throws IOException
628     {
629         _verifyOffsets(array.length, offset, length);
630         // short-cut, do not create child array context etc
631         _verifyValueWrite("write int array");
632         _writeLengthMarker(PREFIX_TYPE_ARRAY, length);
633         for (int i = offset, end = offset+length; i < end; ++i) {
634             _writeDoubleNoCheck(array[i]);
635         }
636     }
637
638     // @since 2.8.8
639     private final void _pushRemainingElements() {
640         if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
641             _elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
642         }
643         _elementCounts[_elementCountsPtr++] = _currentRemainingElements;
644     }
645
646     private final void _writeIntMinimal(int markerBase, int i) throws IOException
647     {
648         _ensureRoomForOutput(5);
649         byte b0;
650         if (i >= 0) {
651             if (i < 24) {
652                 _outputBuffer[_outputTail++] = (byte) (markerBase + i);
653                 return;
654             }
655             if (i <= 0xFF) {
656                 _outputBuffer[_outputTail++] = (byte) (markerBase + SUFFIX_UINT8_ELEMENTS);
657                 _outputBuffer[_outputTail++] = (byte) i;
658                 return;
659             }
660             b0 = (byte) i;
661             i >>= 8;
662             if (i <= 0xFF) {
663                 _outputBuffer[_outputTail++] = (byte) (markerBase + SUFFIX_UINT16_ELEMENTS);
664                 _outputBuffer[_outputTail++] = (byte) i;
665                 _outputBuffer[_outputTail++] = b0;
666                 return;
667             }
668         } else {
669             b0 = (byte) i;
670             i >>= 8;
671         }
672         _outputBuffer[_outputTail++] = (byte) (markerBase + SUFFIX_UINT32_ELEMENTS);
673         _outputBuffer[_outputTail++] = (byte) (i >> 16);
674         _outputBuffer[_outputTail++] = (byte) (i >> 8);
675         _outputBuffer[_outputTail++] = (byte) i;
676         _outputBuffer[_outputTail++] = b0;
677     }
678
679     private final void _writeIntFull(int markerBase, int i) throws IOException
680     {
681         // if ((_outputTail + needed) >= _outputEnd) { _flushBuffer(); }
682         _ensureRoomForOutput(5);
683
684         _outputBuffer[_outputTail++] = (byte) (markerBase + SUFFIX_UINT32_ELEMENTS);
685         _outputBuffer[_outputTail++] = (byte) (i >> 24);
686         _outputBuffer[_outputTail++] = (byte) (i >> 16);
687         _outputBuffer[_outputTail++] = (byte) (i >> 8);
688         _outputBuffer[_outputTail++] = (byte) i;
689     }
690
691     // Helper method that works like `writeNumber(long)` but DOES NOT
692     // check internal output state. It does, however, check need for minimization
693     private final void _writeLongNoCheck(long l) throws IOException {
694         if (_cfgMinimalInts) {
695             if (l >= 0) {
696                 if (l <= 0x100000000L) {
697                     _writeIntMinimal(PREFIX_TYPE_INT_POS, (int) l);
698                     return;
699                 }
700             } else if (l >= -0x100000000L) {
701                 _writeIntMinimal(PREFIX_TYPE_INT_NEG, (int) (-l - 1));
702                 return;
703             }
704         }
705         _ensureRoomForOutput(9);
706         if (l < 0L) {
707             l += 1;
708             l = -l;
709             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_NEG + SUFFIX_UINT64_ELEMENTS);
710         } else {
711             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_POS + SUFFIX_UINT64_ELEMENTS);
712         }
713         int i = (int) (l >> 32);
714         _outputBuffer[_outputTail++] = (byte) (i >> 24);
715         _outputBuffer[_outputTail++] = (byte) (i >> 16);
716         _outputBuffer[_outputTail++] = (byte) (i >> 8);
717         _outputBuffer[_outputTail++] = (byte) i;
718         i = (int) l;
719         _outputBuffer[_outputTail++] = (byte) (i >> 24);
720         _outputBuffer[_outputTail++] = (byte) (i >> 16);
721         _outputBuffer[_outputTail++] = (byte) (i >> 8);
722         _outputBuffer[_outputTail++] = (byte) i;
723     }
724
725     private final void _writeDoubleNoCheck(double d) throws IOException {
726         _ensureRoomForOutput(11);
727         // 17-Apr-2010, tatu: could also use 'doubleToIntBits', but it seems
728         // more accurate to use exact representation; and possibly faster.
729         // However, if there are cases where collapsing of NaN was needed (for
730         // non-Java clients), this can be changed
731         long l = Double.doubleToRawLongBits(d);
732         _outputBuffer[_outputTail++] = BYTE_FLOAT64;
733
734         int i = (int) (l >> 32);
735         _outputBuffer[_outputTail++] = (byte) (i >> 24);
736         _outputBuffer[_outputTail++] = (byte) (i >> 16);
737         _outputBuffer[_outputTail++] = (byte) (i >> 8);
738         _outputBuffer[_outputTail++] = (byte) i;
739         i = (int) l;
740         _outputBuffer[_outputTail++] = (byte) (i >> 24);
741         _outputBuffer[_outputTail++] = (byte) (i >> 16);
742         _outputBuffer[_outputTail++] = (byte) (i >> 8);
743         _outputBuffer[_outputTail++] = (byte) i;
744     }
745
746     /*
747     /***********************************************************
748     /* Output method implementations, textual
749     /***********************************************************
750      */

751
752     @Override
753     public void writeString(String text) throws IOException {
754         if (text == null) {
755             writeNull();
756             return;
757         }
758         _verifyValueWrite("write String value");
759         _writeString(text);
760     }
761
762     @Override
763     public final void writeString(SerializableString sstr) throws IOException {
764         _verifyValueWrite("write String value");
765         byte[] raw = sstr.asUnquotedUTF8();
766         final int len = raw.length;
767         if (len == 0) {
768             _writeByte(BYTE_EMPTY_STRING);
769             return;
770         }
771         _writeLengthMarker(PREFIX_TYPE_TEXT, len);
772         _writeBytes(raw, 0, len);
773     }
774
775     @Override
776     public void writeString(char[] text, int offset, int len)
777             throws IOException {
778         _verifyValueWrite("write String value");
779         if (len == 0) {
780             _writeByte(BYTE_EMPTY_STRING);
781             return;
782         }
783         _writeString(text, offset, len);
784     }
785
786     @Override
787     public void writeRawUTF8String(byte[] raw, int offset, int len)
788             throws IOException
789     {
790         _verifyValueWrite("write String value");
791         if (len == 0) {
792             _writeByte(BYTE_EMPTY_STRING);
793             return;
794         }
795         _writeLengthMarker(PREFIX_TYPE_TEXT, len);
796         _writeBytes(raw, 0, len);
797     }
798
799     @Override
800     public final void writeUTF8String(byte[] text, int offset, int len)
801             throws IOException {
802         // Since no escaping is needed, same as 'writeRawUTF8String'
803         writeRawUTF8String(text, offset, len);
804     }
805
806     /*
807     /**********************************************************
808     /* Output method implementations, unprocessed ("raw")
809     /**********************************************************
810      */

811
812     @Override
813     public void writeRaw(String text) throws IOException {
814         throw _notSupported();
815     }
816
817     @Override
818     public void writeRaw(String text, int offset, int len) throws IOException {
819         throw _notSupported();
820     }
821
822     @Override
823     public void writeRaw(char[] text, int offset, int len) throws IOException {
824         throw _notSupported();
825     }
826
827     @Override
828     public void writeRaw(char c) throws IOException {
829         throw _notSupported();
830     }
831
832     @Override
833     public void writeRawValue(String text) throws IOException {
834         throw _notSupported();
835     }
836
837     @Override
838     public void writeRawValue(String text, int offset, int len)
839             throws IOException {
840         throw _notSupported();
841     }
842
843     @Override
844     public void writeRawValue(char[] text, int offset, int len)
845             throws IOException {
846         throw _notSupported();
847     }
848
849     /*
850      * /********************************************************** /* Output
851      * method implementations, base64-encoded binary
852      * /**********************************************************
853      */

854
855     @Override
856     public void writeBinary(Base64Variant b64variant, byte[] data, int offset,
857             int len) throws IOException {
858         if (data == null) {
859             writeNull();
860             return;
861         }
862         _verifyValueWrite("write Binary value");
863         _writeLengthMarker(PREFIX_TYPE_BYTES, len);
864         _writeBytes(data, offset, len);
865     }
866
867     @Override
868     public int writeBinary(InputStream data, int dataLength) throws IOException {
869         /*
870          * 28-Mar-2014, tatu: Theoretically we could implement encoder that uses
871          * chunking to output binary content of unknown (a priori) length. But
872          * for no let's require knowledge of length, for simplicity: may be
873          * revisited in future.
874          */

875         if (dataLength < 0) {
876             throw new UnsupportedOperationException(
877                     "Must pass actual length for CBOR encoded data");
878         }
879         _verifyValueWrite("write Binary value");
880         int missing;
881
882         _writeLengthMarker(PREFIX_TYPE_BYTES, dataLength);
883         missing = _writeBytes(data, dataLength);
884         if (missing > 0) {
885             _reportError("Too few bytes available: missing " + missing
886                     + " bytes (out of " + dataLength + ")");
887         }
888         return dataLength;
889     }
890
891     @Override
892     public int writeBinary(Base64Variant b64variant, InputStream data,
893             int dataLength) throws IOException {
894         return writeBinary(data, dataLength);
895     }
896
897     /*
898     /**********************************************************
899     /* Output method implementations, primitive
900     /**********************************************************
901      */

902
903     @Override
904     public void writeBoolean(boolean state) throws IOException {
905         _verifyValueWrite("write boolean value");
906         if (state) {
907             _writeByte(BYTE_TRUE);
908         } else {
909             _writeByte(BYTE_FALSE);
910         }
911     }
912
913     @Override
914     public void writeNull() throws IOException {
915         _verifyValueWrite("write null value");
916         _writeByte(BYTE_NULL);
917     }
918
919     @Override
920     public void writeNumber(int i) throws IOException {
921         _verifyValueWrite("write number");
922         int marker;
923         if (i < 0) {
924             i = -i - 1;
925             marker = PREFIX_TYPE_INT_NEG;
926         } else {
927             marker = PREFIX_TYPE_INT_POS;
928         }
929         _ensureRoomForOutput(5);
930         byte b0;
931         if (_cfgMinimalInts) {
932             if (i < 24) {
933                 _outputBuffer[_outputTail++] = (byte) (marker + i);
934                 return;
935             }
936             if (i <= 0xFF) {
937                 _outputBuffer[_outputTail++] = (byte) (marker + SUFFIX_UINT8_ELEMENTS);
938                 _outputBuffer[_outputTail++] = (byte) i;
939                 return;
940             }
941             b0 = (byte) i;
942             i >>= 8;
943             if (i <= 0xFF) {
944                 _outputBuffer[_outputTail++] = (byte) (marker + SUFFIX_UINT16_ELEMENTS);
945                 _outputBuffer[_outputTail++] = (byte) i;
946                 _outputBuffer[_outputTail++] = b0;
947                 return;
948             }
949         } else {
950             b0 = (byte) i;
951             i >>= 8;
952         }
953         _outputBuffer[_outputTail++] = (byte) (marker + SUFFIX_UINT32_ELEMENTS);
954         _outputBuffer[_outputTail++] = (byte) (i >> 16);
955         _outputBuffer[_outputTail++] = (byte) (i >> 8);
956         _outputBuffer[_outputTail++] = (byte) i;
957         _outputBuffer[_outputTail++] = b0;
958     }
959
960     @Override
961     public void writeNumber(long l) throws IOException {
962         _verifyValueWrite("write number");
963         if (_cfgMinimalInts) { // maybe 32 bits is enough?
964             if (l >= 0) {
965                 if (l <= 0x100000000L) {
966                     _writeIntMinimal(PREFIX_TYPE_INT_POS, (int) l);
967                     return;
968                 }
969             } else if (l >= -0x100000000L) {
970                 _writeIntMinimal(PREFIX_TYPE_INT_NEG, (int) (-l - 1));
971                 return;
972             }
973         }
974         _ensureRoomForOutput(9);
975         if (l < 0L) {
976             l += 1;
977             l = -l;
978             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_NEG + SUFFIX_UINT64_ELEMENTS);
979         } else {
980             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_POS + SUFFIX_UINT64_ELEMENTS);
981         }
982         int i = (int) (l >> 32);
983         _outputBuffer[_outputTail++] = (byte) (i >> 24);
984         _outputBuffer[_outputTail++] = (byte) (i >> 16);
985         _outputBuffer[_outputTail++] = (byte) (i >> 8);
986         _outputBuffer[_outputTail++] = (byte) i;
987         i = (int) l;
988         _outputBuffer[_outputTail++] = (byte) (i >> 24);
989         _outputBuffer[_outputTail++] = (byte) (i >> 16);
990         _outputBuffer[_outputTail++] = (byte) (i >> 8);
991         _outputBuffer[_outputTail++] = (byte) i;
992     }
993
994     @Override
995     public void writeNumber(BigInteger v) throws IOException {
996         if (v == null) {
997             writeNull();
998             return;
999         }
1000         _verifyValueWrite("write number");
1001         _write(v);
1002     }
1003
1004     // Main write method isolated so that it can be called directly
1005     // in cases where that is needed (to encode BigDecimal)
1006     protected void _write(BigInteger v) throws IOException {
1007         /*
1008          * Supported by using type tags, as per spec: major type for tag '6'; 5
1009          * LSB either 2 for positive bignum or 3 for negative bignum. And then
1010          * byte sequence that encode variable length integer.
1011          */

1012         if (v.signum() < 0) {
1013             _writeByte(BYTE_TAG_BIGNUM_NEG);
1014             v = v.negate();
1015         } else {
1016             _writeByte(BYTE_TAG_BIGNUM_POS);
1017         }
1018         byte[] data = v.toByteArray();
1019         final int len = data.length;
1020         _writeLengthMarker(PREFIX_TYPE_BYTES, len);
1021         _writeBytes(data, 0, len);
1022     }
1023
1024     @Override
1025     public void writeNumber(double d) throws IOException {
1026         _verifyValueWrite("write number");
1027         _ensureRoomForOutput(11);
1028         /*
1029          * 17-Apr-2010, tatu: could also use 'doubleToIntBits', but it seems
1030          * more accurate to use exact representation; and possibly faster.
1031          * However, if there are cases where collapsing of NaN was needed (for
1032          * non-Java clients), this can be changed
1033          */

1034         long l = Double.doubleToRawLongBits(d);
1035         _outputBuffer[_outputTail++] = BYTE_FLOAT64;
1036
1037         int i = (int) (l >> 32);
1038         _outputBuffer[_outputTail++] = (byte) (i >> 24);
1039         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1040         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1041         _outputBuffer[_outputTail++] = (byte) i;
1042         i = (int) l;
1043         _outputBuffer[_outputTail++] = (byte) (i >> 24);
1044         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1045         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1046         _outputBuffer[_outputTail++] = (byte) i;
1047     }
1048
1049     @Override
1050     public void writeNumber(float f) throws IOException {
1051         // Ok, now, we needed token type byte plus 5 data bytes (7 bits each)
1052         _ensureRoomForOutput(6);
1053         _verifyValueWrite("write number");
1054
1055         /*
1056          * 17-Apr-2010, tatu: could also use 'floatToIntBits', but it seems more
1057          * accurate to use exact representation; and possibly faster. However,
1058          * if there are cases where collapsing of NaN was needed (for non-Java
1059          * clients), this can be changed
1060          */

1061         int i = Float.floatToRawIntBits(f);
1062         _outputBuffer[_outputTail++] = BYTE_FLOAT32;
1063         _outputBuffer[_outputTail++] = (byte) (i >> 24);
1064         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1065         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1066         _outputBuffer[_outputTail++] = (byte) i;
1067     }
1068
1069     @Override
1070     public void writeNumber(BigDecimal dec) throws IOException {
1071         if (dec == null) {
1072             writeNull();
1073             return;
1074         }
1075         _verifyValueWrite("write number");
1076         /* Supported by using type tags, as per spec: major type for tag '6'; 5
1077          * LSB 4. And then a two-element array; integer exponent, and int/bigint
1078          * mantissa
1079          */

1080         // 12-May-2016, tatu: Before 2.8, used "bigfloat", but that was
1081         // incorrect...
1082         _writeByte(BYTE_TAG_DECIMAL_FRACTION);
1083         _writeByte(BYTE_ARRAY_2_ELEMENTS);
1084
1085         // 27-Nov-2019, tatu: As per [dataformats-binary#139] need to change sign here
1086         int scale = dec.scale();
1087         _writeIntValue(-scale);
1088         // Hmmmh. Specification suggest use of regular integer for mantissa. But
1089         // if it doesn't fit, use "bignum"
1090         BigInteger unscaled = dec.unscaledValue();
1091         int bitLength = unscaled.bitLength();
1092         if (bitLength <= 31) {
1093             _writeIntValue(unscaled.intValue());
1094         } else if (bitLength <= 63) {
1095             _writeLongValue(unscaled.longValue());
1096         } else {
1097             _write(unscaled);
1098         }
1099     }
1100
1101     @Override
1102     public void writeNumber(String encodedValue) throws IOException,
1103             JsonGenerationException, UnsupportedOperationException {
1104         // just write as a String -- CBOR does not require schema, so
1105         // databinding
1106         // on receiving end should be able to coerce it appropriately
1107         writeString(encodedValue);
1108     }
1109
1110     /*
1111     /**********************************************************
1112     /* Implementations for other methods
1113     /**********************************************************
1114      */

1115
1116     @Override
1117     protected final void _verifyValueWrite(String typeMsg) throws IOException {
1118         if (!_cborContext.writeValue()) {
1119             _reportError("Can not " + typeMsg + ", expecting field name/id");
1120         }
1121         // decrementElementsRemainingCount()
1122         int count = _currentRemainingElements;
1123         if (count != INDEFINITE_LENGTH) {
1124             --count;
1125
1126             // 28-Jun-2016, tatu: _Should_ check overrun immediately (instead of waiting
1127             //    for end of Object/Array), but has 10% performance penalty for some reason,
1128             //    should figure out why and how to avoid
1129             if (count < 0) {
1130                 _failSizedArrayOrObject();
1131                 return// never gets here
1132             }
1133             _currentRemainingElements = count;
1134         }
1135     }
1136
1137     private void _failSizedArrayOrObject() throws IOException
1138     {
1139         _reportError(String.format("%s size mismatch: number of element encoded is not equal to reported array/map size.",
1140                 _cborContext.typeDesc()));
1141     }
1142
1143     /*
1144     /**********************************************************
1145     /* Low-level output handling
1146     /**********************************************************
1147      */

1148
1149     @Override
1150     public final void flush() throws IOException {
1151         _flushBuffer();
1152         if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
1153             _out.flush();
1154         }
1155     }
1156
1157     @Override
1158     public void close() throws IOException {
1159         // First: let's see that we still have buffers...
1160         if ((_outputBuffer != null)
1161                 && isEnabled(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT)) {
1162             while (true) {
1163                 JsonStreamContext ctxt = getOutputContext();
1164                 if (ctxt.inArray()) {
1165                     writeEndArray();
1166                 } else if (ctxt.inObject()) {
1167                     writeEndObject();
1168                 } else {
1169                     break;
1170                 }
1171             }
1172         }
1173         // boolean wasClosed = _closed;
1174         super.close();
1175         _flushBuffer();
1176
1177         if (_ioContext.isResourceManaged()
1178                 || isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)) {
1179             _out.close();
1180         } else if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
1181             // 14-Jan-2019, tatu: [dataformats-binary#155]: unless prevented via feature
1182             // If we can't close it, we should at least flush
1183             _out.flush();
1184         }
1185         // Internal buffer(s) generator has can now be released as well
1186         _releaseBuffers();
1187     }
1188
1189     /*
1190     /**********************************************************
1191      * Extended API, CBOR-specific encoded output
1192     /**********************************************************
1193      */

1194
1195     /**
1196      * Method for writing out an explicit CBOR Tag.
1197      * 
1198      * @param tagId
1199      *            Positive integer (0 or higher)
1200      * 
1201      * @since 2.5
1202      */

1203     public void writeTag(int tagId) throws IOException {
1204         if (tagId < 0) {
1205             throw new IllegalArgumentException(
1206                     "Can not write negative tag ids (" + tagId + ")");
1207         }
1208         _writeLengthMarker(PREFIX_TYPE_TAG, tagId);
1209     }
1210
1211     /*
1212     /**********************************************************
1213     /* Extended API, raw bytes (by-passing encoder)
1214     /**********************************************************
1215      */

1216
1217     /**
1218      * Method for directly inserting specified byte in output at current
1219      * position.
1220      * <p>
1221      * NOTE: only use this method if you really know what you are doing.
1222      */

1223     public void writeRaw(byte b) throws IOException {
1224         _writeByte(b);
1225     }
1226
1227     /**
1228      * Method for directly inserting specified bytes in output at current
1229      * position.
1230      * <p>
1231      * NOTE: only use this method if you really know what you are doing.
1232      */

1233     public void writeBytes(byte[] data, int offset, int len) throws IOException {
1234         _writeBytes(data, offset, len);
1235     }
1236
1237     /*
1238     /**********************************************************
1239     /* Internal methods: low-level text output
1240     /**********************************************************
1241      */

1242
1243     private final static int MAX_SHORT_STRING_CHARS = 23;
1244     // in case it's > 23 bytes
1245     private final static int MAX_SHORT_STRING_BYTES = 23 * 3 + 2;
1246
1247     private final static int MAX_MEDIUM_STRING_CHARS = 255;
1248     // in case it's > 255 bytes
1249     private final static int MAX_MEDIUM_STRING_BYTES = 255 * 3 + 3;
1250
1251     protected final void _writeString(String name) throws IOException {
1252         int len = name.length();
1253         if (len == 0) {
1254             _writeByte(BYTE_EMPTY_STRING);
1255             return;
1256         }
1257         // Actually, let's not bother with copy for shortest strings
1258         if (len <= MAX_SHORT_STRING_CHARS) {
1259             _ensureSpace(MAX_SHORT_STRING_BYTES); // can afford approximate
1260                                                   // length
1261             int actual = _encode(_outputTail + 1, name, len);
1262             final byte[] buf = _outputBuffer;
1263             int ix = _outputTail;
1264             if (actual <= MAX_SHORT_STRING_CHARS) { // fits in prefix byte
1265                 buf[ix++] = (byte) (PREFIX_TYPE_TEXT + actual);
1266                 _outputTail = ix + actual;
1267                 return;
1268             }
1269             // no, have to move. Blah.
1270             System.arraycopy(buf, ix + 1, buf, ix + 2, actual);
1271             buf[ix++] = BYTE_STRING_1BYTE_LEN;
1272             buf[ix++] = (byte) actual;
1273             _outputTail = ix + actual;
1274             return;
1275         }
1276
1277         char[] cbuf = _charBuffer;
1278         if (len > cbuf.length) {
1279             _charBuffer = cbuf = new char[Math
1280                     .max(_charBuffer.length + 32, len)];
1281         }
1282         name.getChars(0, len, cbuf, 0);
1283         _writeString(cbuf, 0, len);
1284     }
1285
1286     protected final void _ensureSpace(int needed) throws IOException {
1287         if ((_outputTail + needed + 3) > _outputEnd) {
1288             _flushBuffer();
1289         }
1290     }
1291
1292     protected final void _writeString(char[] text, int offset, int len)
1293             throws IOException
1294     {
1295         if (len <= MAX_SHORT_STRING_CHARS) { // possibly short string (not necessarily)
1296             _ensureSpace(MAX_SHORT_STRING_BYTES); // can afford approximate length
1297             int actual = _encode(_outputTail + 1, text, offset, offset + len);
1298             final byte[] buf = _outputBuffer;
1299             int ix = _outputTail;
1300             if (actual <= MAX_SHORT_STRING_CHARS) { // fits in prefix byte
1301                 buf[ix++] = (byte) (PREFIX_TYPE_TEXT + actual);
1302                 _outputTail = ix + actual;
1303                 return;
1304             }
1305             // no, have to move. Blah.
1306             System.arraycopy(buf, ix + 1, buf, ix + 2, actual);
1307             buf[ix++] = BYTE_STRING_1BYTE_LEN;
1308             buf[ix++] = (byte) actual;
1309             _outputTail = ix + actual;
1310             return;
1311         }
1312         if (len <= MAX_MEDIUM_STRING_CHARS) {
1313             _ensureSpace(MAX_MEDIUM_STRING_BYTES); // short enough, can approximate
1314             int actual = _encode(_outputTail + 2, text, offset, offset + len);
1315             final byte[] buf = _outputBuffer;
1316             int ix = _outputTail;
1317             if (actual <= MAX_MEDIUM_STRING_CHARS) { // fits as expected
1318                 buf[ix++] = BYTE_STRING_1BYTE_LEN;
1319                 buf[ix++] = (byte) actual;
1320                 _outputTail = ix + actual;
1321                 return;
1322             }
1323             // no, have to move. Blah.
1324             System.arraycopy(buf, ix + 2, buf, ix + 3, actual);
1325             buf[ix++] = BYTE_STRING_2BYTE_LEN;
1326             buf[ix++] = (byte) (actual >> 8);
1327             buf[ix++] = (byte) actual;
1328             _outputTail = ix + actual;
1329             return;
1330         }
1331         if (len <= MAX_LONG_STRING_CHARS) { // no need to chunk yet
1332             // otherwise, long but single chunk
1333             _ensureSpace(MAX_LONG_STRING_BYTES); // calculate accurate length to
1334                                                  // avoid extra flushing
1335             int ix = _outputTail;
1336             int actual = _encode(ix + 3, text, offset, offset+len);
1337             final byte[] buf = _outputBuffer;
1338             buf[ix++] = BYTE_STRING_2BYTE_LEN;
1339             buf[ix++] = (byte) (actual >> 8);
1340             buf[ix++] = (byte) actual;
1341             _outputTail = ix + actual;
1342             return;
1343         }
1344         _writeChunkedString(text, offset, len);
1345     }
1346
1347     protected final void _writeChunkedString(char[] text, int offset, int len)
1348         throws IOException
1349     {
1350         // need to use a marker first
1351         _writeByte(BYTE_STRING_INDEFINITE);
1352
1353         while (len > MAX_LONG_STRING_CHARS) {
1354             _ensureSpace(MAX_LONG_STRING_BYTES); // marker and single-byte length?
1355             int ix = _outputTail;
1356             int amount = MAX_LONG_STRING_CHARS;
1357
1358             // 23-May-2016, tatu: Make sure NOT to try to split surrogates in half
1359             int end = offset + amount;
1360             char c = text[end-1];
1361             if (c >= SURR1_FIRST && c <= SURR1_LAST) {
1362                 --end;
1363                 --amount;
1364             }
1365             int actual = _encode(_outputTail + 3, text, offset, end);
1366             final byte[] buf = _outputBuffer;
1367             buf[ix++] = BYTE_STRING_2BYTE_LEN;
1368             buf[ix++] = (byte) (actual >> 8);
1369             buf[ix++] = (byte) actual;
1370             _outputTail = ix + actual;
1371             offset += amount;
1372             len -= amount;
1373         }
1374         // and for the last chunk, just use recursion
1375         if (len > 0) {
1376             _writeString(text, offset, len);
1377         }
1378         // plus end marker
1379         _writeByte(BYTE_BREAK);
1380     }
1381
1382     /*
1383     /**********************************************************
1384     /* Internal methods, UTF-8 encoding
1385     /**********************************************************
1386      */

1387
1388     /**
1389      * Helper method called when the whole character sequence is known to fit in
1390      * the output buffer regardless of UTF-8 expansion.
1391      */

1392     private final int _encode(int outputPtr, char[] str, int i, int end) {
1393         // First: let's see if it's all ASCII: that's rather fast
1394         final byte[] outBuf = _outputBuffer;
1395         final int outputStart = outputPtr;
1396         do {
1397             int c = str[i];
1398             if (c > 0x7F) {
1399                 return _shortUTF8Encode2(str, i, end, outputPtr, outputStart);
1400             }
1401             outBuf[outputPtr++] = (byte) c;
1402         } while (++i < end);
1403         return outputPtr - outputStart;
1404     }
1405
1406     /**
1407      * Helper method called when the whole character sequence is known to fit in
1408      * the output buffer, but not all characters are single-byte (ASCII)
1409      * characters.
1410      */

1411     private final int _shortUTF8Encode2(char[] str, int i, int end,
1412             int outputPtr, int outputStart) {
1413         final byte[] outBuf = _outputBuffer;
1414         while (i < end) {
1415             int c = str[i++];
1416             if (c <= 0x7F) {
1417                 outBuf[outputPtr++] = (byte) c;
1418                 continue;
1419             }
1420             // Nope, multi-byte:
1421             if (c < 0x800) { // 2-byte
1422                 outBuf[outputPtr++] = (byte) (0xc0 | (c >> 6));
1423                 outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1424                 continue;
1425             }
1426             // 3 or 4 bytes (surrogate)
1427             // Surrogates?
1428             if (c < SURR1_FIRST || c > SURR2_LAST) { // nope, regular 3-byte character
1429                 outBuf[outputPtr++] = (byte) (0xe0 | (c >> 12));
1430                 outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1431                 outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1432                 continue;
1433             }
1434             // Yup, a surrogate pair
1435             if (c > SURR1_LAST) { // must be from first range; second won't do
1436                 _throwIllegalSurrogate(c);
1437             }
1438             // ... meaning it must have a pair
1439             if (i >= end) {
1440                 _throwIllegalSurrogate(c);
1441             }
1442             c = _convertSurrogate(c, str[i++]);
1443             if (c > 0x10FFFF) { // illegal in JSON as well as in XML
1444                 _throwIllegalSurrogate(c);
1445             }
1446             outBuf[outputPtr++] = (byte) (0xf0 | (c >> 18));
1447             outBuf[outputPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
1448             outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1449             outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1450         }
1451         return (outputPtr - outputStart);
1452     }
1453
1454     private final int _encode(int outputPtr, String str, int len) {
1455         final byte[] outBuf = _outputBuffer;
1456         final int outputStart = outputPtr;
1457
1458         for (int i = 0; i < len; ++i) {
1459             int c = str.charAt(i);
1460             if (c > 0x7F) {
1461                 return _encode2(i, outputPtr, str, len, outputStart);
1462             }
1463             outBuf[outputPtr++] = (byte) c;
1464         }
1465         return (outputPtr - outputStart);
1466     }
1467
1468     private final int _encode2(int i, int outputPtr, String str, int len,
1469             int outputStart) {
1470         final byte[] outBuf = _outputBuffer;
1471         // no; non-ASCII stuff, slower loop
1472         while (i < len) {
1473             int c = str.charAt(i++);
1474             if (c <= 0x7F) {
1475                 outBuf[outputPtr++] = (byte) c;
1476                 continue;
1477             }
1478             // Nope, multi-byte:
1479             if (c < 0x800) { // 2-byte
1480                 outBuf[outputPtr++] = (byte) (0xc0 | (c >> 6));
1481                 outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1482                 continue;
1483             }
1484             // 3 or 4 bytes (surrogate)
1485             // Surrogates?
1486             if (c < SURR1_FIRST || c > SURR2_LAST) { // nope, regular 3-byte
1487                                                      // character
1488                 outBuf[outputPtr++] = (byte) (0xe0 | (c >> 12));
1489                 outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1490                 outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1491                 continue;
1492             }
1493             // Yup, a surrogate pair
1494             if (c > SURR1_LAST) { // must be from first range; second won't do
1495                 _throwIllegalSurrogate(c);
1496             }
1497             // ... meaning it must have a pair
1498             if (i >= len) {
1499                 _throwIllegalSurrogate(c);
1500             }
1501             c = _convertSurrogate(c, str.charAt(i++));
1502             if (c > 0x10FFFF) { // illegal in JSON as well as in XML
1503                 _throwIllegalSurrogate(c);
1504             }
1505             outBuf[outputPtr++] = (byte) (0xf0 | (c >> 18));
1506             outBuf[outputPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
1507             outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
1508             outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f));
1509         }
1510         return (outputPtr - outputStart);
1511     }
1512
1513     /**
1514      * Method called to calculate UTF codepoint, from a surrogate pair.
1515      */

1516     private int _convertSurrogate(int firstPart, int secondPart) {
1517         // Ok, then, is the second part valid?
1518         if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) {
1519             throw new IllegalArgumentException(
1520                     "Broken surrogate pair: first char 0x"
1521                             + Integer.toHexString(firstPart) + ", second 0x"
1522                             + Integer.toHexString(secondPart)
1523                             + "; illegal combination");
1524         }
1525         return 0x10000 + ((firstPart - SURR1_FIRST) << 10)
1526                 + (secondPart - SURR2_FIRST);
1527     }
1528
1529     private void _throwIllegalSurrogate(int code) {
1530         if (code > 0x10FFFF) { // over max?
1531             throw new IllegalArgumentException("Illegal character point (0x"
1532                     + Integer.toHexString(code)
1533                     + ") to output; max is 0x10FFFF as per RFC 4627");
1534         }
1535         if (code >= SURR1_FIRST) {
1536             if (code <= SURR1_LAST) { // Unmatched first part (closing without
1537                                       // second part?)
1538                 throw new IllegalArgumentException(
1539                         "Unmatched first part of surrogate pair (0x"
1540                                 + Integer.toHexString(code) + ")");
1541             }
1542             throw new IllegalArgumentException(
1543                     "Unmatched second part of surrogate pair (0x"
1544                             + Integer.toHexString(code) + ")");
1545         }
1546         // should we ever get this?
1547         throw new IllegalArgumentException("Illegal character point (0x"
1548                 + Integer.toHexString(code) + ") to output");
1549     }
1550
1551     /*
1552     /**********************************************************
1553     /* Internal methods, writing bytes
1554     /**********************************************************
1555      */

1556
1557     private final void _ensureRoomForOutput(int needed) throws IOException {
1558         if ((_outputTail + needed) >= _outputEnd) {
1559             _flushBuffer();
1560         }
1561     }
1562
1563     private final void _writeIntValue(int i) throws IOException {
1564         int marker;
1565         if (i < 0) {
1566             i = -i - 1;
1567             marker = PREFIX_TYPE_INT_NEG;
1568         } else {
1569             marker = PREFIX_TYPE_INT_POS;
1570         }
1571         _writeLengthMarker(marker, i);
1572     }
1573
1574     private final void _writeLongValue(long l) throws IOException {
1575         _ensureRoomForOutput(9);
1576         if (l < 0) {
1577             l += 1;
1578             l = -l;
1579             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_NEG + SUFFIX_UINT64_ELEMENTS);
1580         } else {
1581             _outputBuffer[_outputTail++] = (PREFIX_TYPE_INT_POS + SUFFIX_UINT64_ELEMENTS);
1582         }
1583         int i = (int) (l >> 32);
1584         _outputBuffer[_outputTail++] = (byte) (i >> 24);
1585         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1586         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1587         _outputBuffer[_outputTail++] = (byte) i;
1588         i = (int) l;
1589         _outputBuffer[_outputTail++] = (byte) (i >> 24);
1590         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1591         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1592         _outputBuffer[_outputTail++] = (byte) i;
1593     }
1594
1595     private final void _writeLengthMarker(int majorType, int i)
1596             throws IOException {
1597         _ensureRoomForOutput(5);
1598         if (i < 24) {
1599             _outputBuffer[_outputTail++] = (byte) (majorType + i);
1600             return;
1601         }
1602         if (i <= 0xFF) {
1603             _outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT8_ELEMENTS);
1604             _outputBuffer[_outputTail++] = (byte) i;
1605             return;
1606         }
1607         final byte b0 = (byte) i;
1608         i >>= 8;
1609         if (i <= 0xFF) {
1610             _outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT16_ELEMENTS);
1611             _outputBuffer[_outputTail++] = (byte) i;
1612             _outputBuffer[_outputTail++] = b0;
1613             return;
1614         }
1615         _outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT32_ELEMENTS);
1616         _outputBuffer[_outputTail++] = (byte) (i >> 16);
1617         _outputBuffer[_outputTail++] = (byte) (i >> 8);
1618         _outputBuffer[_outputTail++] = (byte) i;
1619         _outputBuffer[_outputTail++] = b0;
1620     }
1621
1622     private final void _writeByte(byte b) throws IOException {
1623         if (_outputTail >= _outputEnd) {
1624             _flushBuffer();
1625         }
1626         _outputBuffer[_outputTail++] = b;
1627     }
1628
1629     /*
1630      * private final void _writeBytes(byte b1, byte b2) throws IOException { if
1631      * ((_outputTail + 1) >= _outputEnd) { _flushBuffer(); }
1632      * _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; }
1633      */

1634
1635     private final void _writeBytes(byte[] data, int offset, int len)
1636             throws IOException {
1637         if (len == 0) {
1638             return;
1639         }
1640         if ((_outputTail + len) >= _outputEnd) {
1641             _writeBytesLong(data, offset, len);
1642             return;
1643         }
1644         // common case, non-empty, fits in just fine:
1645         System.arraycopy(data, offset, _outputBuffer, _outputTail, len);
1646         _outputTail += len;
1647     }
1648
1649     private final int _writeBytes(InputStream in, int bytesLeft)
1650             throws IOException {
1651         while (bytesLeft > 0) {
1652             int room = _outputEnd - _outputTail;
1653             if (room <= 0) {
1654                 _flushBuffer();
1655                 room = _outputEnd - _outputTail;
1656             }
1657             int count = in.read(_outputBuffer, _outputTail, room);
1658             if (count < 0) {
1659                 break;
1660             }
1661             _outputTail += count;
1662             bytesLeft -= count;
1663         }
1664         return bytesLeft;
1665     }
1666
1667     private final void _writeBytesLong(byte[] data, int offset, int len)
1668             throws IOException {
1669         if (_outputTail >= _outputEnd) {
1670             _flushBuffer();
1671         }
1672         while (true) {
1673             int currLen = Math.min(len, (_outputEnd - _outputTail));
1674             System.arraycopy(data, offset, _outputBuffer, _outputTail, currLen);
1675             _outputTail += currLen;
1676             if ((len -= currLen) == 0) {
1677                 break;
1678             }
1679             offset += currLen;
1680             _flushBuffer();
1681         }
1682     }
1683
1684     /*
1685     /**********************************************************
1686     /* Internal methods, buffer handling
1687     /**********************************************************
1688      */

1689
1690     @Override
1691     protected void _releaseBuffers() {
1692         byte[] buf = _outputBuffer;
1693         if (buf != null && _bufferRecyclable) {
1694             _outputBuffer = null;
1695             _ioContext.releaseWriteEncodingBuffer(buf);
1696         }
1697         char[] cbuf = _charBuffer;
1698         if (cbuf != null) {
1699             _charBuffer = null;
1700             _ioContext.releaseConcatBuffer(cbuf);
1701         }
1702     }
1703
1704     protected final void _flushBuffer() throws IOException {
1705         if (_outputTail > 0) {
1706             _bytesWritten += _outputTail;
1707             _out.write(_outputBuffer, 0, _outputTail);
1708             _outputTail = 0;
1709         }
1710     }
1711
1712     /*
1713     /********************************************************** 
1714     /* Internal methods, size control for array and objects
1715     /**********************************************************
1716     */

1717
1718     private final void closeComplexElement() throws IOException {
1719         switch (_currentRemainingElements) {
1720         case INDEFINITE_LENGTH:
1721             _writeByte(BYTE_BREAK);
1722             break;
1723         case 0: // expected for sized ones
1724             break;
1725         default:
1726             _reportError(String.format("%s size mismatch: expected %d more elements",
1727                     _cborContext.typeDesc(), _currentRemainingElements));
1728         }
1729         _currentRemainingElements = (_elementCountsPtr == 0) 
1730                 ? INDEFINITE_LENGTH
1731                         : _elementCounts[--_elementCountsPtr];
1732     }
1733
1734     /*
1735     /**********************************************************
1736     /* Internal methods, error reporting
1737     /**********************************************************
1738      */

1739
1740     protected UnsupportedOperationException _notSupported() {
1741         return new UnsupportedOperationException();
1742     }
1743 }
1744