1 package com.fasterxml.jackson.core.json;
2
3 import java.io.*;
4 import java.math.BigDecimal;
5 import java.math.BigInteger;
6
7 import com.fasterxml.jackson.core.*;
8 import com.fasterxml.jackson.core.io.CharTypes;
9 import com.fasterxml.jackson.core.io.CharacterEscapes;
10 import com.fasterxml.jackson.core.io.IOContext;
11 import com.fasterxml.jackson.core.io.NumberOutput;
12
13 public class UTF8JsonGenerator
14 extends JsonGeneratorImpl
15 {
16 private final static byte BYTE_u = (byte) 'u';
17
18 private final static byte BYTE_0 = (byte) '0';
19
20 private final static byte BYTE_LBRACKET = (byte) '[';
21 private final static byte BYTE_RBRACKET = (byte) ']';
22 private final static byte BYTE_LCURLY = (byte) '{';
23 private final static byte BYTE_RCURLY = (byte) '}';
24
25 private final static byte BYTE_BACKSLASH = (byte) '\\';
26 private final static byte BYTE_COMMA = (byte) ',';
27 private final static byte BYTE_COLON = (byte) ':';
28
29
30 private final static int MAX_BYTES_TO_BUFFER = 512;
31
32 private final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
33
34 private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' };
35 private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' };
36 private final static byte[] FALSE_BYTES = { 'f', 'a', 'l', 's', 'e' };
37
38
43
44
47 final protected OutputStream _outputStream;
48
49
55 protected byte _quoteChar;
56
57
62
63
67 protected byte[] _outputBuffer;
68
69
73 protected int _outputTail;
74
75
79 protected final int _outputEnd;
80
81
85 protected final int _outputMaxContiguous;
86
87
91 protected char[] _charBuffer;
92
93
96 protected final int _charBufferLength;
97
98
102 protected byte[] _entityBuffer;
103
104
108 protected boolean _bufferRecyclable;
109
110
115
116
119 @SuppressWarnings("deprecation")
120 public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
121 OutputStream out, char quoteChar)
122 {
123 super(ctxt, features, codec);
124 _outputStream = out;
125 _quoteChar = (byte) quoteChar;
126 if (quoteChar != '"') {
127 _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
128 }
129
130 _bufferRecyclable = true;
131 _outputBuffer = ctxt.allocWriteEncodingBuffer();
132 _outputEnd = _outputBuffer.length;
133
134
138 _outputMaxContiguous = _outputEnd >> 3;
139 _charBuffer = ctxt.allocConcatBuffer();
140 _charBufferLength = _charBuffer.length;
141
142
143 if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
144 setHighestNonEscapedChar(127);
145 }
146 }
147
148
151 public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
152 OutputStream out, char quoteChar,
153 byte[] outputBuffer, int outputOffset, boolean bufferRecyclable)
154 {
155
156 super(ctxt, features, codec);
157 _outputStream = out;
158 _quoteChar = (byte) quoteChar;
159 if (quoteChar != '"') {
160 _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
161 }
162
163 _bufferRecyclable = bufferRecyclable;
164 _outputTail = outputOffset;
165 _outputBuffer = outputBuffer;
166 _outputEnd = _outputBuffer.length;
167
168 _outputMaxContiguous = (_outputEnd >> 3);
169 _charBuffer = ctxt.allocConcatBuffer();
170 _charBufferLength = _charBuffer.length;
171 }
172
173 @Deprecated
174 public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
175 OutputStream out) {
176 this(ctxt, features, codec, out, JsonFactory.DEFAULT_QUOTE_CHAR);
177 }
178
179 @Deprecated
180 public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
181 OutputStream out,
182 byte[] outputBuffer, int outputOffset, boolean bufferRecyclable)
183 {
184 this(ctxt, features, codec, out, JsonFactory.DEFAULT_QUOTE_CHAR,
185 outputBuffer, outputOffset, bufferRecyclable);
186 }
187
188
193
194 @Override
195 public Object getOutputTarget() {
196 return _outputStream;
197 }
198
199 @Override
200 public int getOutputBuffered() {
201
202 return _outputTail;
203 }
204
205
210
211 @Override
212 public void writeFieldName(String name) throws IOException
213 {
214 if (_cfgPrettyPrinter != null) {
215 _writePPFieldName(name);
216 return;
217 }
218 final int status = _writeContext.writeFieldName(name);
219 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
220 _reportError("Can not write a field name, expecting a value");
221 }
222 if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
223 if (_outputTail >= _outputEnd) {
224 _flushBuffer();
225 }
226 _outputBuffer[_outputTail++] = BYTE_COMMA;
227 }
228
231 if (_cfgUnqNames) {
232 _writeStringSegments(name, false);
233 return;
234 }
235 final int len = name.length();
236
237 if (len > _charBufferLength) {
238 _writeStringSegments(name, true);
239 return;
240 }
241 if (_outputTail >= _outputEnd) {
242 _flushBuffer();
243 }
244 _outputBuffer[_outputTail++] = _quoteChar;
245
246 if (len <= _outputMaxContiguous) {
247 if ((_outputTail + len) > _outputEnd) {
248 _flushBuffer();
249 }
250 _writeStringSegment(name, 0, len);
251 } else {
252 _writeStringSegments(name, 0, len);
253 }
254
255 if (_outputTail >= _outputEnd) {
256 _flushBuffer();
257 }
258 _outputBuffer[_outputTail++] = _quoteChar;
259 }
260
261 @Override
262 public void writeFieldName(SerializableString name) throws IOException
263 {
264 if (_cfgPrettyPrinter != null) {
265 _writePPFieldName(name);
266 return;
267 }
268 final int status = _writeContext.writeFieldName(name.getValue());
269 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
270 _reportError("Can not write a field name, expecting a value");
271 }
272 if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
273 if (_outputTail >= _outputEnd) {
274 _flushBuffer();
275 }
276 _outputBuffer[_outputTail++] = BYTE_COMMA;
277 }
278 if (_cfgUnqNames) {
279 _writeUnq(name);
280 return;
281 }
282 if (_outputTail >= _outputEnd) {
283 _flushBuffer();
284 }
285 _outputBuffer[_outputTail++] = _quoteChar;
286 int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
287 if (len < 0) {
288 _writeBytes(name.asQuotedUTF8());
289 } else {
290 _outputTail += len;
291 }
292 if (_outputTail >= _outputEnd) {
293 _flushBuffer();
294 }
295 _outputBuffer[_outputTail++] = _quoteChar;
296 }
297
298 private final void _writeUnq(SerializableString name) throws IOException {
299 int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
300 if (len < 0) {
301 _writeBytes(name.asQuotedUTF8());
302 } else {
303 _outputTail += len;
304 }
305 }
306
307
312
313 @Override
314 public final void writeStartArray() throws IOException
315 {
316 _verifyValueWrite("start an array");
317 _writeContext = _writeContext.createChildArrayContext();
318 if (_cfgPrettyPrinter != null) {
319 _cfgPrettyPrinter.writeStartArray(this);
320 } else {
321 if (_outputTail >= _outputEnd) {
322 _flushBuffer();
323 }
324 _outputBuffer[_outputTail++] = BYTE_LBRACKET;
325 }
326 }
327
328 @Override
329 public void writeStartArray(int size) throws IOException
330 {
331 _verifyValueWrite("start an array");
332 _writeContext = _writeContext.createChildArrayContext();
333 if (_cfgPrettyPrinter != null) {
334 _cfgPrettyPrinter.writeStartArray(this);
335 } else {
336 if (_outputTail >= _outputEnd) {
337 _flushBuffer();
338 }
339 _outputBuffer[_outputTail++] = BYTE_LBRACKET;
340 }
341 }
342
343 @Override
344 public final void writeEndArray() throws IOException
345 {
346 if (!_writeContext.inArray()) {
347 _reportError("Current context not Array but "+_writeContext.typeDesc());
348 }
349 if (_cfgPrettyPrinter != null) {
350 _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
351 } else {
352 if (_outputTail >= _outputEnd) {
353 _flushBuffer();
354 }
355 _outputBuffer[_outputTail++] = BYTE_RBRACKET;
356 }
357 _writeContext = _writeContext.clearAndGetParent();
358 }
359
360 @Override
361 public final void writeStartObject() throws IOException
362 {
363 _verifyValueWrite("start an object");
364 _writeContext = _writeContext.createChildObjectContext();
365 if (_cfgPrettyPrinter != null) {
366 _cfgPrettyPrinter.writeStartObject(this);
367 } else {
368 if (_outputTail >= _outputEnd) {
369 _flushBuffer();
370 }
371 _outputBuffer[_outputTail++] = BYTE_LCURLY;
372 }
373 }
374
375 @Override
376 public void writeStartObject(Object forValue) throws IOException
377 {
378 _verifyValueWrite("start an object");
379 JsonWriteContext ctxt = _writeContext.createChildObjectContext(forValue);
380 _writeContext = ctxt;
381 if (_cfgPrettyPrinter != null) {
382 _cfgPrettyPrinter.writeStartObject(this);
383 } else {
384 if (_outputTail >= _outputEnd) {
385 _flushBuffer();
386 }
387 _outputBuffer[_outputTail++] = '{';
388 }
389 }
390
391 @Override
392 public final void writeEndObject() throws IOException
393 {
394 if (!_writeContext.inObject()) {
395 _reportError("Current context not Object but "+_writeContext.typeDesc());
396 }
397 if (_cfgPrettyPrinter != null) {
398 _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
399 } else {
400 if (_outputTail >= _outputEnd) {
401 _flushBuffer();
402 }
403 _outputBuffer[_outputTail++] = BYTE_RCURLY;
404 }
405 _writeContext = _writeContext.clearAndGetParent();
406 }
407
408
412 protected final void _writePPFieldName(String name) throws IOException
413 {
414 int status = _writeContext.writeFieldName(name);
415 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
416 _reportError("Can not write a field name, expecting a value");
417 }
418 if ((status == JsonWriteContext.STATUS_OK_AFTER_COMMA)) {
419 _cfgPrettyPrinter.writeObjectEntrySeparator(this);
420 } else {
421 _cfgPrettyPrinter.beforeObjectEntries(this);
422 }
423 if (_cfgUnqNames) {
424 _writeStringSegments(name, false);
425 return;
426 }
427 final int len = name.length();
428 if (len > _charBufferLength) {
429 _writeStringSegments(name, true);
430 return;
431 }
432 if (_outputTail >= _outputEnd) {
433 _flushBuffer();
434 }
435 _outputBuffer[_outputTail++] = _quoteChar;
436 name.getChars(0, len, _charBuffer, 0);
437
438 if (len <= _outputMaxContiguous) {
439 if ((_outputTail + len) > _outputEnd) {
440 _flushBuffer();
441 }
442 _writeStringSegment(_charBuffer, 0, len);
443 } else {
444 _writeStringSegments(_charBuffer, 0, len);
445 }
446 if (_outputTail >= _outputEnd) {
447 _flushBuffer();
448 }
449 _outputBuffer[_outputTail++] = _quoteChar;
450 }
451
452 protected final void _writePPFieldName(SerializableString name) throws IOException
453 {
454 final int status = _writeContext.writeFieldName(name.getValue());
455 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
456 _reportError("Can not write a field name, expecting a value");
457 }
458 if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
459 _cfgPrettyPrinter.writeObjectEntrySeparator(this);
460 } else {
461 _cfgPrettyPrinter.beforeObjectEntries(this);
462 }
463
464 final boolean addQuotes = !_cfgUnqNames;
465 if (addQuotes) {
466 if (_outputTail >= _outputEnd) {
467 _flushBuffer();
468 }
469 _outputBuffer[_outputTail++] = _quoteChar;
470 }
471 int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
472 if (len < 0) {
473 _writeBytes(name.asQuotedUTF8());
474 } else {
475 _outputTail += len;
476 }
477 if (addQuotes) {
478 if (_outputTail >= _outputEnd) {
479 _flushBuffer();
480 }
481 _outputBuffer[_outputTail++] = _quoteChar;
482 }
483 }
484
485
490
491 @Override
492 public void writeString(String text) throws IOException
493 {
494 _verifyValueWrite(WRITE_STRING);
495 if (text == null) {
496 _writeNull();
497 return;
498 }
499
500 final int len = text.length();
501 if (len > _outputMaxContiguous) {
502 _writeStringSegments(text, true);
503 return;
504 }
505 if ((_outputTail + len) >= _outputEnd) {
506 _flushBuffer();
507 }
508 _outputBuffer[_outputTail++] = _quoteChar;
509 _writeStringSegment(text, 0, len);
510 if (_outputTail >= _outputEnd) {
511 _flushBuffer();
512 }
513 _outputBuffer[_outputTail++] = _quoteChar;
514 }
515
516 @Override
517 public void writeString(Reader reader, int len) throws IOException {
518 _verifyValueWrite(WRITE_STRING);
519 if (reader == null) {
520 _reportError("null reader");
521 }
522
523 int toRead = (len >= 0) ? len : Integer.MAX_VALUE;
524
525 final char[] buf = _charBuffer;
526
527
528 if (_outputTail >= _outputEnd) {
529 _flushBuffer();
530 }
531 _outputBuffer[_outputTail++] = _quoteChar;
532
533
534 while (toRead > 0){
535 int toReadNow = Math.min(toRead, buf.length);
536 int numRead = reader.read(buf, 0, toReadNow);
537 if(numRead <= 0){
538 break;
539 }
540 if ((_outputTail + len) >= _outputEnd) {
541 _flushBuffer();
542 }
543 _writeStringSegments(buf, 0, numRead);
544
545 toRead -= numRead;
546 }
547
548
549 if (_outputTail >= _outputEnd) {
550 _flushBuffer();
551 }
552 _outputBuffer[_outputTail++] = _quoteChar;
553
554 if (toRead > 0 && len >= 0){
555 _reportError("Didn't read enough from reader");
556 }
557 }
558
559 @Override
560 public void writeString(char[] text, int offset, int len) throws IOException
561 {
562 _verifyValueWrite(WRITE_STRING);
563 if (_outputTail >= _outputEnd) {
564 _flushBuffer();
565 }
566 _outputBuffer[_outputTail++] = _quoteChar;
567
568 if (len <= _outputMaxContiguous) {
569 if ((_outputTail + len) > _outputEnd) {
570 _flushBuffer();
571 }
572 _writeStringSegment(text, offset, len);
573 } else {
574 _writeStringSegments(text, offset, len);
575 }
576
577 if (_outputTail >= _outputEnd) {
578 _flushBuffer();
579 }
580 _outputBuffer[_outputTail++] = _quoteChar;
581 }
582
583 @Override
584 public final void writeString(SerializableString text) throws IOException
585 {
586 _verifyValueWrite(WRITE_STRING);
587 if (_outputTail >= _outputEnd) {
588 _flushBuffer();
589 }
590 _outputBuffer[_outputTail++] = _quoteChar;
591 int len = text.appendQuotedUTF8(_outputBuffer, _outputTail);
592 if (len < 0) {
593 _writeBytes(text.asQuotedUTF8());
594 } else {
595 _outputTail += len;
596 }
597 if (_outputTail >= _outputEnd) {
598 _flushBuffer();
599 }
600 _outputBuffer[_outputTail++] = _quoteChar;
601 }
602
603 @Override
604 public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException
605 {
606 _verifyValueWrite(WRITE_STRING);
607 if (_outputTail >= _outputEnd) {
608 _flushBuffer();
609 }
610 _outputBuffer[_outputTail++] = _quoteChar;
611 _writeBytes(text, offset, length);
612 if (_outputTail >= _outputEnd) {
613 _flushBuffer();
614 }
615 _outputBuffer[_outputTail++] = _quoteChar;
616 }
617
618 @Override
619 public void writeUTF8String(byte[] text, int offset, int len) throws IOException
620 {
621 _verifyValueWrite(WRITE_STRING);
622 if (_outputTail >= _outputEnd) {
623 _flushBuffer();
624 }
625 _outputBuffer[_outputTail++] = _quoteChar;
626
627 if (len <= _outputMaxContiguous) {
628 _writeUTF8Segment(text, offset, len);
629 } else {
630 _writeUTF8Segments(text, offset, len);
631 }
632 if (_outputTail >= _outputEnd) {
633 _flushBuffer();
634 }
635 _outputBuffer[_outputTail++] = _quoteChar;
636 }
637
638
643
644 @Override
645 public void writeRaw(String text) throws IOException {
646 final int len = text.length();
647 final char[] buf = _charBuffer;
648 if (len <= buf.length) {
649 text.getChars(0, len, buf, 0);
650 writeRaw(buf, 0, len);
651 } else {
652 writeRaw(text, 0, len);
653 }
654 }
655
656 @Override
657 public void writeRaw(String text, int offset, int len) throws IOException
658 {
659 final char[] buf = _charBuffer;
660 final int cbufLen = buf.length;
661
662
663 if (len <= cbufLen) {
664 text.getChars(offset, offset+len, buf, 0);
665 writeRaw(buf, 0, len);
666 return;
667 }
668
669
670
671
672 final int maxChunk = Math.min(cbufLen,
673 (_outputEnd >> 2) + (_outputEnd >> 4));
674 final int maxBytes = maxChunk * 3;
675
676 while (len > 0) {
677 int len2 = Math.min(maxChunk, len);
678 text.getChars(offset, offset+len2, buf, 0);
679 if ((_outputTail + maxBytes) > _outputEnd) {
680 _flushBuffer();
681 }
682
683
684
685
686
687
688 if (len2 > 1) {
689 char ch = buf[len2-1];
690 if ((ch >= SURR1_FIRST) && (ch <= SURR1_LAST)) {
691 --len2;
692 }
693 }
694 _writeRawSegment(buf, 0, len2);
695 offset += len2;
696 len -= len2;
697 }
698 }
699
700 @Override
701 public void writeRaw(SerializableString text) throws IOException
702 {
703 int len = text.appendUnquotedUTF8(_outputBuffer, _outputTail);
704 if (len < 0) {
705 _writeBytes(text.asUnquotedUTF8());
706 } else {
707 _outputTail += len;
708 }
709 }
710
711
712 @Override
713 public void writeRawValue(SerializableString text) throws IOException {
714 _verifyValueWrite(WRITE_RAW);
715 int len = text.appendUnquotedUTF8(_outputBuffer, _outputTail);
716 if (len < 0) {
717 _writeBytes(text.asUnquotedUTF8());
718 } else {
719 _outputTail += len;
720 }
721 }
722
723
724 @Override
725 public final void writeRaw(char[] cbuf, int offset, int len) throws IOException
726 {
727
728 {
729 int len3 = len+len+len;
730 if ((_outputTail + len3) > _outputEnd) {
731
732 if (_outputEnd < len3) {
733 _writeSegmentedRaw(cbuf, offset, len);
734 return;
735 }
736
737 _flushBuffer();
738 }
739 }
740 len += offset;
741
742
743 main_loop:
744 while (offset < len) {
745 inner_loop:
746 while (true) {
747 int ch = (int) cbuf[offset];
748 if (ch > 0x7F) {
749 break inner_loop;
750 }
751 _outputBuffer[_outputTail++] = (byte) ch;
752 if (++offset >= len) {
753 break main_loop;
754 }
755 }
756 char ch = cbuf[offset++];
757 if (ch < 0x800) {
758 _outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
759 _outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
760 } else {
761 offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
762 }
763 }
764 }
765
766 @Override
767 public void writeRaw(char ch) throws IOException
768 {
769 if ((_outputTail + 3) >= _outputEnd) {
770 _flushBuffer();
771 }
772 final byte[] bbuf = _outputBuffer;
773 if (ch <= 0x7F) {
774 bbuf[_outputTail++] = (byte) ch;
775 } else if (ch < 0x800) {
776 bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
777 bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
778 } else {
779 _outputRawMultiByteChar(ch, null, 0, 0);
780 }
781 }
782
783
787 private final void _writeSegmentedRaw(char[] cbuf, int offset, int len) throws IOException
788 {
789 final int end = _outputEnd;
790 final byte[] bbuf = _outputBuffer;
791 final int inputEnd = offset + len;
792
793 main_loop:
794 while (offset < inputEnd) {
795 inner_loop:
796 while (true) {
797 int ch = (int) cbuf[offset];
798 if (ch >= 0x80) {
799 break inner_loop;
800 }
801
802 if (_outputTail >= end) {
803 _flushBuffer();
804 }
805 bbuf[_outputTail++] = (byte) ch;
806 if (++offset >= inputEnd) {
807 break main_loop;
808 }
809 }
810 if ((_outputTail + 3) >= _outputEnd) {
811 _flushBuffer();
812 }
813 char ch = cbuf[offset++];
814 if (ch < 0x800) {
815 bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
816 bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
817 } else {
818 offset = _outputRawMultiByteChar(ch, cbuf, offset, inputEnd);
819 }
820 }
821 }
822
823
832 private void _writeRawSegment(char[] cbuf, int offset, int end) throws IOException
833 {
834 main_loop:
835 while (offset < end) {
836 inner_loop:
837 while (true) {
838 int ch = (int) cbuf[offset];
839 if (ch > 0x7F) {
840 break inner_loop;
841 }
842 _outputBuffer[_outputTail++] = (byte) ch;
843 if (++offset >= end) {
844 break main_loop;
845 }
846 }
847 char ch = cbuf[offset++];
848 if (ch < 0x800) {
849 _outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
850 _outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
851 } else {
852 offset = _outputRawMultiByteChar(ch, cbuf, offset, end);
853 }
854 }
855 }
856
857
862
863 @Override
864 public void writeBinary(Base64Variant b64variant,
865 byte[] data, int offset, int len)
866 throws IOException, JsonGenerationException
867 {
868 _verifyValueWrite(WRITE_BINARY);
869
870 if (_outputTail >= _outputEnd) {
871 _flushBuffer();
872 }
873 _outputBuffer[_outputTail++] = _quoteChar;
874 _writeBinary(b64variant, data, offset, offset+len);
875
876 if (_outputTail >= _outputEnd) {
877 _flushBuffer();
878 }
879 _outputBuffer[_outputTail++] = _quoteChar;
880 }
881
882 @Override
883 public int writeBinary(Base64Variant b64variant,
884 InputStream data, int dataLength)
885 throws IOException, JsonGenerationException
886 {
887 _verifyValueWrite(WRITE_BINARY);
888
889 if (_outputTail >= _outputEnd) {
890 _flushBuffer();
891 }
892 _outputBuffer[_outputTail++] = _quoteChar;
893 byte[] encodingBuffer = _ioContext.allocBase64Buffer();
894 int bytes;
895 try {
896 if (dataLength < 0) {
897 bytes = _writeBinary(b64variant, data, encodingBuffer);
898 } else {
899 int missing = _writeBinary(b64variant, data, encodingBuffer, dataLength);
900 if (missing > 0) {
901 _reportError("Too few bytes available: missing "+missing+" bytes (out of "+dataLength+")");
902 }
903 bytes = dataLength;
904 }
905 } finally {
906 _ioContext.releaseBase64Buffer(encodingBuffer);
907 }
908
909 if (_outputTail >= _outputEnd) {
910 _flushBuffer();
911 }
912 _outputBuffer[_outputTail++] = _quoteChar;
913 return bytes;
914 }
915
916
921
922 @Override
923 public void writeNumber(short s) throws IOException
924 {
925 _verifyValueWrite(WRITE_NUMBER);
926
927 if ((_outputTail + 6) >= _outputEnd) {
928 _flushBuffer();
929 }
930 if (_cfgNumbersAsStrings) {
931 _writeQuotedShort(s);
932 return;
933 }
934 _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
935 }
936
937 private final void _writeQuotedShort(short s) throws IOException {
938 if ((_outputTail + 8) >= _outputEnd) {
939 _flushBuffer();
940 }
941 _outputBuffer[_outputTail++] = _quoteChar;
942 _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
943 _outputBuffer[_outputTail++] = _quoteChar;
944 }
945
946 @Override
947 public void writeNumber(int i) throws IOException
948 {
949 _verifyValueWrite(WRITE_NUMBER);
950
951 if ((_outputTail + 11) >= _outputEnd) {
952 _flushBuffer();
953 }
954 if (_cfgNumbersAsStrings) {
955 _writeQuotedInt(i);
956 return;
957 }
958 _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
959 }
960
961 private final void _writeQuotedInt(int i) throws IOException
962 {
963 if ((_outputTail + 13) >= _outputEnd) {
964 _flushBuffer();
965 }
966 _outputBuffer[_outputTail++] = _quoteChar;
967 _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
968 _outputBuffer[_outputTail++] = _quoteChar;
969 }
970
971 @Override
972 public void writeNumber(long l) throws IOException
973 {
974 _verifyValueWrite(WRITE_NUMBER);
975 if (_cfgNumbersAsStrings) {
976 _writeQuotedLong(l);
977 return;
978 }
979 if ((_outputTail + 21) >= _outputEnd) {
980
981 _flushBuffer();
982 }
983 _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
984 }
985
986 private final void _writeQuotedLong(long l) throws IOException
987 {
988 if ((_outputTail + 23) >= _outputEnd) {
989 _flushBuffer();
990 }
991 _outputBuffer[_outputTail++] = _quoteChar;
992 _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
993 _outputBuffer[_outputTail++] = _quoteChar;
994 }
995
996 @Override
997 public void writeNumber(BigInteger value) throws IOException
998 {
999 _verifyValueWrite(WRITE_NUMBER);
1000 if (value == null) {
1001 _writeNull();
1002 } else if (_cfgNumbersAsStrings) {
1003 _writeQuotedRaw(value.toString());
1004 } else {
1005 writeRaw(value.toString());
1006 }
1007 }
1008
1009 @SuppressWarnings("deprecation")
1010 @Override
1011 public void writeNumber(double d) throws IOException
1012 {
1013 if (_cfgNumbersAsStrings ||
1014 (NumberOutput.notFinite(d)
1015 && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features))) {
1016 writeString(String.valueOf(d));
1017 return;
1018 }
1019
1020 _verifyValueWrite(WRITE_NUMBER);
1021 writeRaw(String.valueOf(d));
1022 }
1023
1024 @SuppressWarnings("deprecation")
1025 @Override
1026 public void writeNumber(float f) throws IOException
1027 {
1028 if (_cfgNumbersAsStrings ||
1029 (NumberOutput.notFinite(f)
1030 && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features))) {
1031 writeString(String.valueOf(f));
1032 return;
1033 }
1034
1035 _verifyValueWrite(WRITE_NUMBER);
1036 writeRaw(String.valueOf(f));
1037 }
1038
1039 @Override
1040 public void writeNumber(BigDecimal value) throws IOException
1041 {
1042
1043 _verifyValueWrite(WRITE_NUMBER);
1044 if (value == null) {
1045 _writeNull();
1046 } else if (_cfgNumbersAsStrings) {
1047 _writeQuotedRaw(_asString(value));
1048 } else {
1049 writeRaw(_asString(value));
1050 }
1051 }
1052
1053 @Override
1054 public void writeNumber(String encodedValue) throws IOException
1055 {
1056 _verifyValueWrite(WRITE_NUMBER);
1057 if (_cfgNumbersAsStrings) {
1058 _writeQuotedRaw(encodedValue);
1059 } else {
1060 writeRaw(encodedValue);
1061 }
1062 }
1063
1064 @Override
1065 public void writeNumber(char[] encodedValueBuffer, int offset, int length) throws IOException {
1066 _verifyValueWrite(WRITE_NUMBER);
1067 if (_cfgNumbersAsStrings) {
1068 _writeQuotedRaw(encodedValueBuffer, offset, length);
1069 } else {
1070 writeRaw(encodedValueBuffer, offset, length);
1071 }
1072 }
1073
1074 private final void _writeQuotedRaw(String value) throws IOException
1075 {
1076 if (_outputTail >= _outputEnd) {
1077 _flushBuffer();
1078 }
1079 _outputBuffer[_outputTail++] = _quoteChar;
1080 writeRaw(value);
1081 if (_outputTail >= _outputEnd) {
1082 _flushBuffer();
1083 }
1084 _outputBuffer[_outputTail++] = _quoteChar;
1085 }
1086
1087 private void _writeQuotedRaw(char[] text, int offset, int length) throws IOException
1088 {
1089 if (_outputTail >= _outputEnd) {
1090 _flushBuffer();
1091 }
1092 _outputBuffer[_outputTail++] = _quoteChar;
1093 writeRaw(text, offset, length);
1094 if (_outputTail >= _outputEnd) {
1095 _flushBuffer();
1096 }
1097 _outputBuffer[_outputTail++] = _quoteChar;
1098 }
1099
1100 @Override
1101 public void writeBoolean(boolean state) throws IOException
1102 {
1103 _verifyValueWrite(WRITE_BOOLEAN);
1104 if ((_outputTail + 5) >= _outputEnd) {
1105 _flushBuffer();
1106 }
1107 byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES;
1108 int len = keyword.length;
1109 System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len);
1110 _outputTail += len;
1111 }
1112
1113 @Override
1114 public void writeNull() throws IOException
1115 {
1116 _verifyValueWrite(WRITE_NULL);
1117 _writeNull();
1118 }
1119
1120
1125
1126 @Override
1127 protected final void _verifyValueWrite(String typeMsg) throws IOException
1128 {
1129 final int status = _writeContext.writeValue();
1130 if (_cfgPrettyPrinter != null) {
1131
1132 _verifyPrettyValueWrite(typeMsg, status);
1133 return;
1134 }
1135 byte b;
1136 switch (status) {
1137 case JsonWriteContext.STATUS_OK_AS_IS:
1138 default:
1139 return;
1140 case JsonWriteContext.STATUS_OK_AFTER_COMMA:
1141 b = BYTE_COMMA;
1142 break;
1143 case JsonWriteContext.STATUS_OK_AFTER_COLON:
1144 b = BYTE_COLON;
1145 break;
1146 case JsonWriteContext.STATUS_OK_AFTER_SPACE:
1147 if (_rootValueSeparator != null) {
1148 byte[] raw = _rootValueSeparator.asUnquotedUTF8();
1149 if (raw.length > 0) {
1150 _writeBytes(raw);
1151 }
1152 }
1153 return;
1154 case JsonWriteContext.STATUS_EXPECT_NAME:
1155 _reportCantWriteValueExpectName(typeMsg);
1156 return;
1157 }
1158 if (_outputTail >= _outputEnd) {
1159 _flushBuffer();
1160 }
1161 _outputBuffer[_outputTail++] = b;
1162 }
1163
1164
1169
1170 @Override
1171 public void flush() throws IOException
1172 {
1173 _flushBuffer();
1174 if (_outputStream != null) {
1175 if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
1176 _outputStream.flush();
1177 }
1178 }
1179 }
1180
1181 @Override
1182 public void close() throws IOException
1183 {
1184 super.close();
1185
1186
1189
1190 if ((_outputBuffer != null)
1191 && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
1192 while (true) {
1193 JsonStreamContext ctxt = getOutputContext();
1194 if (ctxt.inArray()) {
1195 writeEndArray();
1196 } else if (ctxt.inObject()) {
1197 writeEndObject();
1198 } else {
1199 break;
1200 }
1201 }
1202 }
1203 _flushBuffer();
1204 _outputTail = 0;
1205
1206
1212 if (_outputStream != null) {
1213 if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
1214 _outputStream.close();
1215 } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
1216
1217 _outputStream.flush();
1218 }
1219 }
1220
1221 _releaseBuffers();
1222 }
1223
1224 @Override
1225 protected void _releaseBuffers()
1226 {
1227 byte[] buf = _outputBuffer;
1228 if (buf != null && _bufferRecyclable) {
1229 _outputBuffer = null;
1230 _ioContext.releaseWriteEncodingBuffer(buf);
1231 }
1232 char[] cbuf = _charBuffer;
1233 if (cbuf != null) {
1234 _charBuffer = null;
1235 _ioContext.releaseConcatBuffer(cbuf);
1236 }
1237 }
1238
1239
1244
1245 private final void _writeBytes(byte[] bytes) throws IOException
1246 {
1247 final int len = bytes.length;
1248 if ((_outputTail + len) > _outputEnd) {
1249 _flushBuffer();
1250
1251 if (len > MAX_BYTES_TO_BUFFER) {
1252 _outputStream.write(bytes, 0, len);
1253 return;
1254 }
1255 }
1256 System.arraycopy(bytes, 0, _outputBuffer, _outputTail, len);
1257 _outputTail += len;
1258 }
1259
1260 private final void _writeBytes(byte[] bytes, int offset, int len) throws IOException
1261 {
1262 if ((_outputTail + len) > _outputEnd) {
1263 _flushBuffer();
1264
1265 if (len > MAX_BYTES_TO_BUFFER) {
1266 _outputStream.write(bytes, offset, len);
1267 return;
1268 }
1269 }
1270 System.arraycopy(bytes, offset, _outputBuffer, _outputTail, len);
1271 _outputTail += len;
1272 }
1273
1274
1279
1280
1287 private final void _writeStringSegments(String text, boolean addQuotes) throws IOException
1288 {
1289 if (addQuotes) {
1290 if (_outputTail >= _outputEnd) {
1291 _flushBuffer();
1292 }
1293 _outputBuffer[_outputTail++] = _quoteChar;
1294 }
1295
1296 int left = text.length();
1297 int offset = 0;
1298
1299 while (left > 0) {
1300 int len = Math.min(_outputMaxContiguous, left);
1301 if ((_outputTail + len) > _outputEnd) {
1302 _flushBuffer();
1303 }
1304 _writeStringSegment(text, offset, len);
1305 offset += len;
1306 left -= len;
1307 }
1308
1309 if (addQuotes) {
1310 if (_outputTail >= _outputEnd) {
1311 _flushBuffer();
1312 }
1313 _outputBuffer[_outputTail++] = _quoteChar;
1314 }
1315 }
1316
1317
1323 private final void _writeStringSegments(char[] cbuf, int offset, int totalLen) throws IOException
1324 {
1325 do {
1326 int len = Math.min(_outputMaxContiguous, totalLen);
1327 if ((_outputTail + len) > _outputEnd) {
1328 _flushBuffer();
1329 }
1330 _writeStringSegment(cbuf, offset, len);
1331 offset += len;
1332 totalLen -= len;
1333 } while (totalLen > 0);
1334 }
1335
1336 private final void _writeStringSegments(String text, int offset, int totalLen) throws IOException
1337 {
1338 do {
1339 int len = Math.min(_outputMaxContiguous, totalLen);
1340 if ((_outputTail + len) > _outputEnd) {
1341 _flushBuffer();
1342 }
1343 _writeStringSegment(text, offset, len);
1344 offset += len;
1345 totalLen -= len;
1346 } while (totalLen > 0);
1347 }
1348
1349
1354
1355
1363 private final void _writeStringSegment(char[] cbuf, int offset, int len)
1364 throws IOException
1365 {
1366
1367
1368
1369 len += offset;
1370
1371 int outputPtr = _outputTail;
1372 final byte[] outputBuffer = _outputBuffer;
1373 final int[] escCodes = _outputEscapes;
1374
1375 while (offset < len) {
1376 int ch = cbuf[offset];
1377
1378 if (ch > 0x7F || escCodes[ch] != 0) {
1379 break;
1380 }
1381 outputBuffer[outputPtr++] = (byte) ch;
1382 ++offset;
1383 }
1384 _outputTail = outputPtr;
1385 if (offset < len) {
1386 if (_characterEscapes != null) {
1387 _writeCustomStringSegment2(cbuf, offset, len);
1388 } else if (_maximumNonEscapedChar == 0) {
1389 _writeStringSegment2(cbuf, offset, len);
1390 } else {
1391 _writeStringSegmentASCII2(cbuf, offset, len);
1392 }
1393
1394 }
1395 }
1396
1397 private final void _writeStringSegment(String text, int offset, int len) throws IOException
1398 {
1399
1400
1401 len += offset;
1402
1403 int outputPtr = _outputTail;
1404 final byte[] outputBuffer = _outputBuffer;
1405 final int[] escCodes = _outputEscapes;
1406
1407 while (offset < len) {
1408 int ch = text.charAt(offset);
1409
1410 if (ch > 0x7F || escCodes[ch] != 0) {
1411 break;
1412 }
1413 outputBuffer[outputPtr++] = (byte) ch;
1414 ++offset;
1415 }
1416 _outputTail = outputPtr;
1417 if (offset < len) {
1418 if (_characterEscapes != null) {
1419 _writeCustomStringSegment2(text, offset, len);
1420 } else if (_maximumNonEscapedChar == 0) {
1421 _writeStringSegment2(text, offset, len);
1422 } else {
1423 _writeStringSegmentASCII2(text, offset, len);
1424 }
1425 }
1426 }
1427
1428
1432 private final void _writeStringSegment2(final char[] cbuf, int offset, final int end) throws IOException
1433 {
1434
1435 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1436 _flushBuffer();
1437 }
1438
1439 int outputPtr = _outputTail;
1440
1441 final byte[] outputBuffer = _outputBuffer;
1442 final int[] escCodes = _outputEscapes;
1443
1444 while (offset < end) {
1445 int ch = cbuf[offset++];
1446 if (ch <= 0x7F) {
1447 if (escCodes[ch] == 0) {
1448 outputBuffer[outputPtr++] = (byte) ch;
1449 continue;
1450 }
1451 int escape = escCodes[ch];
1452 if (escape > 0) {
1453 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1454 outputBuffer[outputPtr++] = (byte) escape;
1455 } else {
1456
1457 outputPtr = _writeGenericEscape(ch, outputPtr);
1458 }
1459 continue;
1460 }
1461 if (ch <= 0x7FF) {
1462 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1463 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1464 } else {
1465 outputPtr = _outputMultiByteChar(ch, outputPtr);
1466 }
1467 }
1468 _outputTail = outputPtr;
1469 }
1470
1471 private final void _writeStringSegment2(final String text, int offset, final int end) throws IOException
1472 {
1473 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1474 _flushBuffer();
1475 }
1476
1477 int outputPtr = _outputTail;
1478
1479 final byte[] outputBuffer = _outputBuffer;
1480 final int[] escCodes = _outputEscapes;
1481
1482 while (offset < end) {
1483 int ch = text.charAt(offset++);
1484 if (ch <= 0x7F) {
1485 if (escCodes[ch] == 0) {
1486 outputBuffer[outputPtr++] = (byte) ch;
1487 continue;
1488 }
1489 int escape = escCodes[ch];
1490 if (escape > 0) {
1491 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1492 outputBuffer[outputPtr++] = (byte) escape;
1493 } else {
1494
1495 outputPtr = _writeGenericEscape(ch, outputPtr);
1496 }
1497 continue;
1498 }
1499 if (ch <= 0x7FF) {
1500 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1501 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1502 } else {
1503 outputPtr = _outputMultiByteChar(ch, outputPtr);
1504 }
1505 }
1506 _outputTail = outputPtr;
1507 }
1508
1509
1515
1516
1520 private final void _writeStringSegmentASCII2(final char[] cbuf, int offset, final int end) throws IOException
1521 {
1522
1523 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1524 _flushBuffer();
1525 }
1526 int outputPtr = _outputTail;
1527
1528 final byte[] outputBuffer = _outputBuffer;
1529 final int[] escCodes = _outputEscapes;
1530 final int maxUnescaped = _maximumNonEscapedChar;
1531
1532 while (offset < end) {
1533 int ch = cbuf[offset++];
1534 if (ch <= 0x7F) {
1535 if (escCodes[ch] == 0) {
1536 outputBuffer[outputPtr++] = (byte) ch;
1537 continue;
1538 }
1539 int escape = escCodes[ch];
1540 if (escape > 0) {
1541 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1542 outputBuffer[outputPtr++] = (byte) escape;
1543 } else {
1544
1545 outputPtr = _writeGenericEscape(ch, outputPtr);
1546 }
1547 continue;
1548 }
1549 if (ch > maxUnescaped) {
1550 outputPtr = _writeGenericEscape(ch, outputPtr);
1551 continue;
1552 }
1553 if (ch <= 0x7FF) {
1554 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1555 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1556 } else {
1557 outputPtr = _outputMultiByteChar(ch, outputPtr);
1558 }
1559 }
1560 _outputTail = outputPtr;
1561 }
1562
1563 private final void _writeStringSegmentASCII2(final String text, int offset, final int end) throws IOException
1564 {
1565
1566 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1567 _flushBuffer();
1568 }
1569
1570 int outputPtr = _outputTail;
1571
1572 final byte[] outputBuffer = _outputBuffer;
1573 final int[] escCodes = _outputEscapes;
1574 final int maxUnescaped = _maximumNonEscapedChar;
1575
1576 while (offset < end) {
1577 int ch = text.charAt(offset++);
1578 if (ch <= 0x7F) {
1579 if (escCodes[ch] == 0) {
1580 outputBuffer[outputPtr++] = (byte) ch;
1581 continue;
1582 }
1583 int escape = escCodes[ch];
1584 if (escape > 0) {
1585 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1586 outputBuffer[outputPtr++] = (byte) escape;
1587 } else {
1588
1589 outputPtr = _writeGenericEscape(ch, outputPtr);
1590 }
1591 continue;
1592 }
1593 if (ch > maxUnescaped) {
1594 outputPtr = _writeGenericEscape(ch, outputPtr);
1595 continue;
1596 }
1597 if (ch <= 0x7FF) {
1598 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1599 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1600 } else {
1601 outputPtr = _outputMultiByteChar(ch, outputPtr);
1602 }
1603 }
1604 _outputTail = outputPtr;
1605 }
1606
1607
1613
1614
1618 private final void _writeCustomStringSegment2(final char[] cbuf, int offset, final int end) throws IOException
1619 {
1620
1621 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1622 _flushBuffer();
1623 }
1624 int outputPtr = _outputTail;
1625
1626 final byte[] outputBuffer = _outputBuffer;
1627 final int[] escCodes = _outputEscapes;
1628
1629 final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
1630 final CharacterEscapes customEscapes = _characterEscapes;
1631
1632 while (offset < end) {
1633 int ch = cbuf[offset++];
1634 if (ch <= 0x7F) {
1635 if (escCodes[ch] == 0) {
1636 outputBuffer[outputPtr++] = (byte) ch;
1637 continue;
1638 }
1639 int escape = escCodes[ch];
1640 if (escape > 0) {
1641 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1642 outputBuffer[outputPtr++] = (byte) escape;
1643 } else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
1644 SerializableString esc = customEscapes.getEscapeSequence(ch);
1645 if (esc == null) {
1646 _reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
1647 +Integer.toHexString(ch)+", although was supposed to have one");
1648 }
1649 outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
1650 } else {
1651
1652 outputPtr = _writeGenericEscape(ch, outputPtr);
1653 }
1654 continue;
1655 }
1656 if (ch > maxUnescaped) {
1657 outputPtr = _writeGenericEscape(ch, outputPtr);
1658 continue;
1659 }
1660 SerializableString esc = customEscapes.getEscapeSequence(ch);
1661 if (esc != null) {
1662 outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
1663 continue;
1664 }
1665 if (ch <= 0x7FF) {
1666 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1667 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1668 } else {
1669 outputPtr = _outputMultiByteChar(ch, outputPtr);
1670 }
1671 }
1672 _outputTail = outputPtr;
1673 }
1674
1675 private final void _writeCustomStringSegment2(final String text, int offset, final int end) throws IOException
1676 {
1677
1678 if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
1679 _flushBuffer();
1680 }
1681 int outputPtr = _outputTail;
1682
1683 final byte[] outputBuffer = _outputBuffer;
1684 final int[] escCodes = _outputEscapes;
1685
1686 final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
1687 final CharacterEscapes customEscapes = _characterEscapes;
1688
1689 while (offset < end) {
1690 int ch = text.charAt(offset++);
1691 if (ch <= 0x7F) {
1692 if (escCodes[ch] == 0) {
1693 outputBuffer[outputPtr++] = (byte) ch;
1694 continue;
1695 }
1696 int escape = escCodes[ch];
1697 if (escape > 0) {
1698 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1699 outputBuffer[outputPtr++] = (byte) escape;
1700 } else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
1701 SerializableString esc = customEscapes.getEscapeSequence(ch);
1702 if (esc == null) {
1703 _reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
1704 +Integer.toHexString(ch)+", although was supposed to have one");
1705 }
1706 outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
1707 } else {
1708
1709 outputPtr = _writeGenericEscape(ch, outputPtr);
1710 }
1711 continue;
1712 }
1713 if (ch > maxUnescaped) {
1714 outputPtr = _writeGenericEscape(ch, outputPtr);
1715 continue;
1716 }
1717 SerializableString esc = customEscapes.getEscapeSequence(ch);
1718 if (esc != null) {
1719 outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
1720 continue;
1721 }
1722 if (ch <= 0x7FF) {
1723 outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
1724 outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
1725 } else {
1726 outputPtr = _outputMultiByteChar(ch, outputPtr);
1727 }
1728 }
1729 _outputTail = outputPtr;
1730 }
1731
1732 private final int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars)
1733 throws IOException, JsonGenerationException
1734 {
1735 byte[] raw = esc.asUnquotedUTF8();
1736 int len = raw.length;
1737 if (len > 6) {
1738 return _handleLongCustomEscape(outputBuffer, outputPtr, _outputEnd, raw, remainingChars);
1739 }
1740
1741 System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
1742 return (outputPtr + len);
1743 }
1744
1745 private final int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd,
1746 byte[] raw, int remainingChars)
1747 throws IOException, JsonGenerationException
1748 {
1749 final int len = raw.length;
1750 if ((outputPtr + len) > outputEnd) {
1751 _outputTail = outputPtr;
1752 _flushBuffer();
1753 outputPtr = _outputTail;
1754 if (len > outputBuffer.length) {
1755 _outputStream.write(raw, 0, len);
1756 return outputPtr;
1757 }
1758 }
1759 System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
1760 outputPtr += len;
1761
1762 if ((outputPtr + 6 * remainingChars) > outputEnd) {
1763 _outputTail = outputPtr;
1764 _flushBuffer();
1765 return _outputTail;
1766 }
1767 return outputPtr;
1768 }
1769
1770
1775
1776
1781 private final void _writeUTF8Segments(byte[] utf8, int offset, int totalLen)
1782 throws IOException, JsonGenerationException
1783 {
1784 do {
1785 int len = Math.min(_outputMaxContiguous, totalLen);
1786 _writeUTF8Segment(utf8, offset, len);
1787 offset += len;
1788 totalLen -= len;
1789 } while (totalLen > 0);
1790 }
1791
1792 private final void _writeUTF8Segment(byte[] utf8, final int offset, final int len)
1793 throws IOException, JsonGenerationException
1794 {
1795
1796 final int[] escCodes = _outputEscapes;
1797
1798 for (int ptr = offset, end = offset + len; ptr < end; ) {
1799
1800 int ch = utf8[ptr++];
1801 if ((ch >= 0) && escCodes[ch] != 0) {
1802 _writeUTF8Segment2(utf8, offset, len);
1803 return;
1804 }
1805 }
1806
1807
1808 if ((_outputTail + len) > _outputEnd) {
1809 _flushBuffer();
1810 }
1811 System.arraycopy(utf8, offset, _outputBuffer, _outputTail, len);
1812 _outputTail += len;
1813 }
1814
1815 private final void _writeUTF8Segment2(final byte[] utf8, int offset, int len)
1816 throws IOException, JsonGenerationException
1817 {
1818 int outputPtr = _outputTail;
1819
1820
1821 if ((outputPtr + (len * 6)) > _outputEnd) {
1822 _flushBuffer();
1823 outputPtr = _outputTail;
1824 }
1825
1826 final byte[] outputBuffer = _outputBuffer;
1827 final int[] escCodes = _outputEscapes;
1828 len += offset;
1829
1830 while (offset < len) {
1831 byte b = utf8[offset++];
1832 int ch = b;
1833 if (ch < 0 || escCodes[ch] == 0) {
1834 outputBuffer[outputPtr++] = b;
1835 continue;
1836 }
1837 int escape = escCodes[ch];
1838 if (escape > 0) {
1839 outputBuffer[outputPtr++] = BYTE_BACKSLASH;
1840 outputBuffer[outputPtr++] = (byte) escape;
1841 } else {
1842
1843 outputPtr = _writeGenericEscape(ch, outputPtr);
1844 }
1845 }
1846 _outputTail = outputPtr;
1847 }
1848
1849
1854
1855 protected final void _writeBinary(Base64Variant b64variant,
1856 byte[] input, int inputPtr, final int inputEnd)
1857 throws IOException, JsonGenerationException
1858 {
1859
1860 int safeInputEnd = inputEnd - 3;
1861
1862 int safeOutputEnd = _outputEnd - 6;
1863 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1864
1865
1866 while (inputPtr <= safeInputEnd) {
1867 if (_outputTail > safeOutputEnd) {
1868 _flushBuffer();
1869 }
1870
1871 int b24 = ((int) input[inputPtr++]) << 8;
1872 b24 |= ((int) input[inputPtr++]) & 0xFF;
1873 b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
1874 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1875 if (--chunksBeforeLF <= 0) {
1876
1877 _outputBuffer[_outputTail++] = '\\';
1878 _outputBuffer[_outputTail++] = 'n';
1879 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1880 }
1881 }
1882
1883
1884 int inputLeft = inputEnd - inputPtr;
1885 if (inputLeft > 0) {
1886 if (_outputTail > safeOutputEnd) {
1887 _flushBuffer();
1888 }
1889 int b24 = ((int) input[inputPtr++]) << 16;
1890 if (inputLeft == 2) {
1891 b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
1892 }
1893 _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
1894 }
1895 }
1896
1897
1898 protected final int _writeBinary(Base64Variant b64variant,
1899 InputStream data, byte[] readBuffer, int bytesLeft)
1900 throws IOException, JsonGenerationException
1901 {
1902 int inputPtr = 0;
1903 int inputEnd = 0;
1904 int lastFullOffset = -3;
1905
1906
1907 int safeOutputEnd = _outputEnd - 6;
1908 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1909
1910 while (bytesLeft > 2) {
1911 if (inputPtr > lastFullOffset) {
1912 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
1913 inputPtr = 0;
1914 if (inputEnd < 3) {
1915 break;
1916 }
1917 lastFullOffset = inputEnd-3;
1918 }
1919 if (_outputTail > safeOutputEnd) {
1920 _flushBuffer();
1921 }
1922 int b24 = ((int) readBuffer[inputPtr++]) << 8;
1923 b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
1924 b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
1925 bytesLeft -= 3;
1926 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1927 if (--chunksBeforeLF <= 0) {
1928 _outputBuffer[_outputTail++] = '\\';
1929 _outputBuffer[_outputTail++] = 'n';
1930 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1931 }
1932 }
1933
1934
1935 if (bytesLeft > 0) {
1936 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
1937 inputPtr = 0;
1938 if (inputEnd > 0) {
1939 if (_outputTail > safeOutputEnd) {
1940 _flushBuffer();
1941 }
1942 int b24 = ((int) readBuffer[inputPtr++]) << 16;
1943 int amount;
1944 if (inputPtr < inputEnd) {
1945 b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
1946 amount = 2;
1947 } else {
1948 amount = 1;
1949 }
1950 _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
1951 bytesLeft -= amount;
1952 }
1953 }
1954 return bytesLeft;
1955 }
1956
1957
1958 protected final int _writeBinary(Base64Variant b64variant,
1959 InputStream data, byte[] readBuffer)
1960 throws IOException, JsonGenerationException
1961 {
1962 int inputPtr = 0;
1963 int inputEnd = 0;
1964 int lastFullOffset = -3;
1965 int bytesDone = 0;
1966
1967
1968 int safeOutputEnd = _outputEnd - 6;
1969 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1970
1971
1972 while (true) {
1973 if (inputPtr > lastFullOffset) {
1974 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
1975 inputPtr = 0;
1976 if (inputEnd < 3) {
1977 break;
1978 }
1979 lastFullOffset = inputEnd-3;
1980 }
1981 if (_outputTail > safeOutputEnd) {
1982 _flushBuffer();
1983 }
1984
1985 int b24 = ((int) readBuffer[inputPtr++]) << 8;
1986 b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
1987 b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
1988 bytesDone += 3;
1989 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1990 if (--chunksBeforeLF <= 0) {
1991 _outputBuffer[_outputTail++] = '\\';
1992 _outputBuffer[_outputTail++] = 'n';
1993 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1994 }
1995 }
1996
1997
1998 if (inputPtr < inputEnd) {
1999 if (_outputTail > safeOutputEnd) {
2000 _flushBuffer();
2001 }
2002 int b24 = ((int) readBuffer[inputPtr++]) << 16;
2003 int amount = 1;
2004 if (inputPtr < inputEnd) {
2005 b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
2006 amount = 2;
2007 }
2008 bytesDone += amount;
2009 _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
2010 }
2011 return bytesDone;
2012 }
2013
2014 private final int _readMore(InputStream in,
2015 byte[] readBuffer, int inputPtr, int inputEnd,
2016 int maxRead) throws IOException
2017 {
2018
2019 int i = 0;
2020 while (inputPtr < inputEnd) {
2021 readBuffer[i++] = readBuffer[inputPtr++];
2022 }
2023 inputPtr = 0;
2024 inputEnd = i;
2025 maxRead = Math.min(maxRead, readBuffer.length);
2026
2027 do {
2028 int length = maxRead - inputEnd;
2029 if (length == 0) {
2030 break;
2031 }
2032 int count = in.read(readBuffer, inputEnd, length);
2033 if (count < 0) {
2034 return inputEnd;
2035 }
2036 inputEnd += count;
2037 } while (inputEnd < 3);
2038 return inputEnd;
2039 }
2040
2041
2046
2047
2052 private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputEnd)
2053 throws IOException
2054 {
2055
2056 if (ch >= SURR1_FIRST) {
2057 if (ch <= SURR2_LAST) {
2058
2059 if (inputOffset >= inputEnd || cbuf == null) {
2060 _reportError(String.format(
2061 "Split surrogate on writeRaw() input (last character): first character 0x%4x", ch));
2062 }
2063 _outputSurrogates(ch, cbuf[inputOffset]);
2064 return inputOffset+1;
2065 }
2066 }
2067 final byte[] bbuf = _outputBuffer;
2068 bbuf[_outputTail++] = (byte) (0xe0 | (ch >> 12));
2069 bbuf[_outputTail++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
2070 bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
2071 return inputOffset;
2072 }
2073
2074 protected final void _outputSurrogates(int surr1, int surr2) throws IOException
2075 {
2076 int c = _decodeSurrogate(surr1, surr2);
2077 if ((_outputTail + 4) > _outputEnd) {
2078 _flushBuffer();
2079 }
2080 final byte[] bbuf = _outputBuffer;
2081 bbuf[_outputTail++] = (byte) (0xf0 | (c >> 18));
2082 bbuf[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f));
2083 bbuf[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f));
2084 bbuf[_outputTail++] = (byte) (0x80 | (c & 0x3f));
2085 }
2086
2087
2096 private final int _outputMultiByteChar(int ch, int outputPtr) throws IOException
2097 {
2098 byte[] bbuf = _outputBuffer;
2099 if (ch >= SURR1_FIRST && ch <= SURR2_LAST) {
2100
2101
2102
2103
2104 bbuf[outputPtr++] = BYTE_BACKSLASH;
2105 bbuf[outputPtr++] = BYTE_u;
2106
2107 bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
2108 bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
2109 bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
2110 bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
2111
2112 } else {
2113 bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12));
2114 bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
2115 bbuf[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
2116 }
2117 return outputPtr;
2118 }
2119
2120 private final void _writeNull() throws IOException
2121 {
2122 if ((_outputTail + 4) >= _outputEnd) {
2123 _flushBuffer();
2124 }
2125 System.arraycopy(NULL_BYTES, 0, _outputBuffer, _outputTail, 4);
2126 _outputTail += 4;
2127 }
2128
2129
2134 private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException
2135 {
2136 final byte[] bbuf = _outputBuffer;
2137 bbuf[outputPtr++] = BYTE_BACKSLASH;
2138 bbuf[outputPtr++] = BYTE_u;
2139 if (charToEscape > 0xFF) {
2140 int hi = (charToEscape >> 8) & 0xFF;
2141 bbuf[outputPtr++] = HEX_CHARS[hi >> 4];
2142 bbuf[outputPtr++] = HEX_CHARS[hi & 0xF];
2143 charToEscape &= 0xFF;
2144 } else {
2145 bbuf[outputPtr++] = BYTE_0;
2146 bbuf[outputPtr++] = BYTE_0;
2147 }
2148
2149 bbuf[outputPtr++] = HEX_CHARS[charToEscape >> 4];
2150 bbuf[outputPtr++] = HEX_CHARS[charToEscape & 0xF];
2151 return outputPtr;
2152 }
2153
2154 protected final void _flushBuffer() throws IOException
2155 {
2156 int len = _outputTail;
2157 if (len > 0) {
2158 _outputTail = 0;
2159 _outputStream.write(_outputBuffer, 0, len);
2160 }
2161 }
2162 }
2163