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
17 public class WriterBasedJsonGenerator
18 extends JsonGeneratorImpl
19 {
20 final protected static int SHORT_WRITE = 32;
21
22 final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
23
24
29
30 final protected Writer _writer;
31
32
36 protected char _quoteChar;
37
38
43
44
48 protected char[] _outputBuffer;
49
50
53 protected int _outputHead;
54
55
59 protected int _outputTail;
60
61
65 protected int _outputEnd;
66
67
71 protected char[] _entityBuffer;
72
73
77 protected SerializableString _currentEscape;
78
79
85 protected char[] _copyBuffer;
86
87
92
93 @Deprecated
94 public WriterBasedJsonGenerator(IOContext ctxt, int features,
95 ObjectCodec codec, Writer w) {
96 this(ctxt, features, codec, w, JsonFactory.DEFAULT_QUOTE_CHAR);
97 }
98
99
102 public WriterBasedJsonGenerator(IOContext ctxt, int features,
103 ObjectCodec codec, Writer w,
104 char quoteChar)
105
106 {
107 super(ctxt, features, codec);
108 _writer = w;
109 _outputBuffer = ctxt.allocConcatBuffer();
110 _outputEnd = _outputBuffer.length;
111 _quoteChar = quoteChar;
112 if (quoteChar != '"') {
113 _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
114 }
115 }
116
117
122
123 @Override
124 public Object getOutputTarget() {
125 return _writer;
126 }
127
128 @Override
129 public int getOutputBuffered() {
130
131 int len = _outputTail - _outputHead;
132 return Math.max(0, len);
133 }
134
135
136 @Override
137 public boolean canWriteFormattedNumbers() { return true; }
138
139
144
145 @Override
146 public void writeFieldName(String name) throws IOException
147 {
148 int status = _writeContext.writeFieldName(name);
149 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
150 _reportError("Can not write a field name, expecting a value");
151 }
152 _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
153 }
154
155 @Override
156 public void writeFieldName(SerializableString name) throws IOException
157 {
158
159 int status = _writeContext.writeFieldName(name.getValue());
160 if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
161 _reportError("Can not write a field name, expecting a value");
162 }
163 _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
164 }
165
166 protected final void _writeFieldName(String name, boolean commaBefore) throws IOException
167 {
168 if (_cfgPrettyPrinter != null) {
169 _writePPFieldName(name, commaBefore);
170 return;
171 }
172
173 if ((_outputTail + 1) >= _outputEnd) {
174 _flushBuffer();
175 }
176 if (commaBefore) {
177 _outputBuffer[_outputTail++] = ',';
178 }
179
180 if (_cfgUnqNames) {
181 _writeString(name);
182 return;
183 }
184
185 _outputBuffer[_outputTail++] = _quoteChar;
186
187 _writeString(name);
188
189 if (_outputTail >= _outputEnd) {
190 _flushBuffer();
191 }
192 _outputBuffer[_outputTail++] = _quoteChar;
193 }
194
195 protected final void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
196 {
197 if (_cfgPrettyPrinter != null) {
198 _writePPFieldName(name, commaBefore);
199 return;
200 }
201
202 if ((_outputTail + 1) >= _outputEnd) {
203 _flushBuffer();
204 }
205 if (commaBefore) {
206 _outputBuffer[_outputTail++] = ',';
207 }
208
209 if (_cfgUnqNames) {
210 final char[] ch = name.asQuotedChars();
211 writeRaw(ch, 0, ch.length);
212 return;
213 }
214
215 _outputBuffer[_outputTail++] = _quoteChar;
216
217
218 int len = name.appendQuoted(_outputBuffer, _outputTail);
219 if (len < 0) {
220 _writeFieldNameTail(name);
221 return;
222 }
223 _outputTail += len;
224 if (_outputTail >= _outputEnd) {
225 _flushBuffer();
226 }
227 _outputBuffer[_outputTail++] = _quoteChar;
228 }
229
230 private final void _writeFieldNameTail(SerializableString name) throws IOException
231 {
232 final char[] quoted = name.asQuotedChars();
233 writeRaw(quoted, 0, quoted.length);
234 if (_outputTail >= _outputEnd) {
235 _flushBuffer();
236 }
237 _outputBuffer[_outputTail++] = _quoteChar;
238 }
239
240
245
246 @Override
247 public void writeStartArray() throws IOException
248 {
249 _verifyValueWrite("start an array");
250 _writeContext = _writeContext.createChildArrayContext();
251 if (_cfgPrettyPrinter != null) {
252 _cfgPrettyPrinter.writeStartArray(this);
253 } else {
254 if (_outputTail >= _outputEnd) {
255 _flushBuffer();
256 }
257 _outputBuffer[_outputTail++] = '[';
258 }
259 }
260
261 @Override
262 public void writeStartArray(int size) throws IOException
263 {
264 _verifyValueWrite("start an array");
265 _writeContext = _writeContext.createChildArrayContext();
266 if (_cfgPrettyPrinter != null) {
267 _cfgPrettyPrinter.writeStartArray(this);
268 } else {
269 if (_outputTail >= _outputEnd) {
270 _flushBuffer();
271 }
272 _outputBuffer[_outputTail++] = '[';
273 }
274 }
275
276 @Override
277 public void writeEndArray() throws IOException
278 {
279 if (!_writeContext.inArray()) {
280 _reportError("Current context not Array but "+_writeContext.typeDesc());
281 }
282 if (_cfgPrettyPrinter != null) {
283 _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
284 } else {
285 if (_outputTail >= _outputEnd) {
286 _flushBuffer();
287 }
288 _outputBuffer[_outputTail++] = ']';
289 }
290 _writeContext = _writeContext.clearAndGetParent();
291 }
292
293 @Override
294 public void writeStartObject() throws IOException
295 {
296 _verifyValueWrite("start an object");
297 _writeContext = _writeContext.createChildObjectContext();
298 if (_cfgPrettyPrinter != null) {
299 _cfgPrettyPrinter.writeStartObject(this);
300 } else {
301 if (_outputTail >= _outputEnd) {
302 _flushBuffer();
303 }
304 _outputBuffer[_outputTail++] = '{';
305 }
306 }
307
308 @Override
309 public void writeStartObject(Object forValue) throws IOException
310 {
311 _verifyValueWrite("start an object");
312 JsonWriteContext ctxt = _writeContext.createChildObjectContext(forValue);
313 _writeContext = ctxt;
314 if (_cfgPrettyPrinter != null) {
315 _cfgPrettyPrinter.writeStartObject(this);
316 } else {
317 if (_outputTail >= _outputEnd) {
318 _flushBuffer();
319 }
320 _outputBuffer[_outputTail++] = '{';
321 }
322 }
323
324 @Override
325 public void writeEndObject() throws IOException
326 {
327 if (!_writeContext.inObject()) {
328 _reportError("Current context not Object but "+_writeContext.typeDesc());
329 }
330 if (_cfgPrettyPrinter != null) {
331 _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
332 } else {
333 if (_outputTail >= _outputEnd) {
334 _flushBuffer();
335 }
336 _outputBuffer[_outputTail++] = '}';
337 }
338 _writeContext = _writeContext.clearAndGetParent();
339 }
340
341
345 protected final void _writePPFieldName(String name, boolean commaBefore) throws IOException
346 {
347 if (commaBefore) {
348 _cfgPrettyPrinter.writeObjectEntrySeparator(this);
349 } else {
350 _cfgPrettyPrinter.beforeObjectEntries(this);
351 }
352
353 if (_cfgUnqNames) {
354 _writeString(name);
355 } else {
356 if (_outputTail >= _outputEnd) {
357 _flushBuffer();
358 }
359 _outputBuffer[_outputTail++] = _quoteChar;
360 _writeString(name);
361 if (_outputTail >= _outputEnd) {
362 _flushBuffer();
363 }
364 _outputBuffer[_outputTail++] = _quoteChar;
365 }
366 }
367
368 protected final void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
369 {
370 if (commaBefore) {
371 _cfgPrettyPrinter.writeObjectEntrySeparator(this);
372 } else {
373 _cfgPrettyPrinter.beforeObjectEntries(this);
374 }
375 final char[] quoted = name.asQuotedChars();
376 if (_cfgUnqNames) {
377 writeRaw(quoted, 0, quoted.length);
378 } else {
379 if (_outputTail >= _outputEnd) {
380 _flushBuffer();
381 }
382 _outputBuffer[_outputTail++] = _quoteChar;
383 writeRaw(quoted, 0, quoted.length);
384 if (_outputTail >= _outputEnd) {
385 _flushBuffer();
386 }
387 _outputBuffer[_outputTail++] = _quoteChar;
388 }
389 }
390
391
396
397 @Override
398 public void writeString(String text) throws IOException
399 {
400 _verifyValueWrite(WRITE_STRING);
401 if (text == null) {
402 _writeNull();
403 return;
404 }
405 if (_outputTail >= _outputEnd) {
406 _flushBuffer();
407 }
408 _outputBuffer[_outputTail++] = _quoteChar;
409 _writeString(text);
410
411 if (_outputTail >= _outputEnd) {
412 _flushBuffer();
413 }
414 _outputBuffer[_outputTail++] = _quoteChar;
415 }
416
417 @Override
418 public void writeString(Reader reader, int len) throws IOException {
419 _verifyValueWrite(WRITE_STRING);
420 if (reader == null) {
421 _reportError("null reader");
422 }
423 int toRead = (len >= 0) ? len : Integer.MAX_VALUE;
424
425 if ((_outputTail + len) >= _outputEnd) {
426 _flushBuffer();
427 }
428 _outputBuffer[_outputTail++] = _quoteChar;
429
430 final char[] buf = _allocateCopyBuffer();
431
432 while (toRead > 0) {
433 int toReadNow = Math.min(toRead, buf.length);
434 int numRead = reader.read(buf, 0, toReadNow);
435 if (numRead <= 0) {
436 break;
437 }
438 if ((_outputTail + len) >= _outputEnd) {
439 _flushBuffer();
440 }
441 _writeString(buf, 0, numRead);
442
443
444 toRead -= numRead;
445 }
446
447 if ((_outputTail + len) >= _outputEnd) {
448 _flushBuffer();
449 }
450 _outputBuffer[_outputTail++] = _quoteChar;
451
452 if (toRead > 0 && len >= 0) {
453 _reportError("Didn't read enough from reader");
454 }
455 }
456
457 @Override
458 public void writeString(char[] text, int offset, int len) throws IOException
459 {
460 _verifyValueWrite(WRITE_STRING);
461 if (_outputTail >= _outputEnd) {
462 _flushBuffer();
463 }
464 _outputBuffer[_outputTail++] = _quoteChar;
465 _writeString(text, offset, len);
466
467 if (_outputTail >= _outputEnd) {
468 _flushBuffer();
469 }
470 _outputBuffer[_outputTail++] = _quoteChar;
471 }
472
473 @Override
474 public void writeString(SerializableString sstr) throws IOException
475 {
476 _verifyValueWrite(WRITE_STRING);
477 if (_outputTail >= _outputEnd) {
478 _flushBuffer();
479 }
480 _outputBuffer[_outputTail++] = _quoteChar;
481 int len = sstr.appendQuoted(_outputBuffer, _outputTail);
482 if (len < 0) {
483 _writeString2(sstr);
484 return;
485 }
486 _outputTail += len;
487 if (_outputTail >= _outputEnd) {
488 _flushBuffer();
489 }
490 _outputBuffer[_outputTail++] = _quoteChar;
491 }
492
493 private void _writeString2(SerializableString sstr) throws IOException
494 {
495
496 char[] text = sstr.asQuotedChars();
497 final int len = text.length;
498 if (len < SHORT_WRITE) {
499 int room = _outputEnd - _outputTail;
500 if (len > room) {
501 _flushBuffer();
502 }
503 System.arraycopy(text, 0, _outputBuffer, _outputTail, len);
504 _outputTail += len;
505 } else {
506 _flushBuffer();
507 _writer.write(text, 0, len);
508 }
509 if (_outputTail >= _outputEnd) {
510 _flushBuffer();
511 }
512 _outputBuffer[_outputTail++] = _quoteChar;
513 }
514
515 @Override
516 public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException {
517
518 _reportUnsupportedOperation();
519 }
520
521 @Override
522 public void writeUTF8String(byte[] text, int offset, int length) throws IOException {
523
524 _reportUnsupportedOperation();
525 }
526
527
532
533 @Override
534 public void writeRaw(String text) throws IOException
535 {
536
537 int len = text.length();
538 int room = _outputEnd - _outputTail;
539
540 if (room == 0) {
541 _flushBuffer();
542 room = _outputEnd - _outputTail;
543 }
544
545 if (room >= len) {
546 text.getChars(0, len, _outputBuffer, _outputTail);
547 _outputTail += len;
548 } else {
549 writeRawLong(text);
550 }
551 }
552
553 @Override
554 public void writeRaw(String text, int start, int len) throws IOException
555 {
556
557 int room = _outputEnd - _outputTail;
558
559 if (room < len) {
560 _flushBuffer();
561 room = _outputEnd - _outputTail;
562 }
563
564 if (room >= len) {
565 text.getChars(start, start+len, _outputBuffer, _outputTail);
566 _outputTail += len;
567 } else {
568 writeRawLong(text.substring(start, start+len));
569 }
570 }
571
572
573 @Override
574 public void writeRaw(SerializableString text) throws IOException {
575 int len = text.appendUnquoted(_outputBuffer, _outputTail);
576 if (len < 0) {
577 writeRaw(text.getValue());
578 return;
579 }
580 _outputTail += len;
581 }
582
583 @Override
584 public void writeRaw(char[] text, int offset, int len) throws IOException
585 {
586
587 if (len < SHORT_WRITE) {
588 int room = _outputEnd - _outputTail;
589 if (len > room) {
590 _flushBuffer();
591 }
592 System.arraycopy(text, offset, _outputBuffer, _outputTail, len);
593 _outputTail += len;
594 return;
595 }
596
597 _flushBuffer();
598 _writer.write(text, offset, len);
599 }
600
601 @Override
602 public void writeRaw(char c) throws IOException
603 {
604 if (_outputTail >= _outputEnd) {
605 _flushBuffer();
606 }
607 _outputBuffer[_outputTail++] = c;
608 }
609
610 private void writeRawLong(String text) throws IOException
611 {
612 int room = _outputEnd - _outputTail;
613
614 text.getChars(0, room, _outputBuffer, _outputTail);
615 _outputTail += room;
616 _flushBuffer();
617 int offset = room;
618 int len = text.length() - room;
619
620 while (len > _outputEnd) {
621 int amount = _outputEnd;
622 text.getChars(offset, offset+amount, _outputBuffer, 0);
623 _outputHead = 0;
624 _outputTail = amount;
625 _flushBuffer();
626 offset += amount;
627 len -= amount;
628 }
629
630 text.getChars(offset, offset+len, _outputBuffer, 0);
631 _outputHead = 0;
632 _outputTail = len;
633 }
634
635
640
641 @Override
642 public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len)
643 throws IOException, JsonGenerationException
644 {
645 _verifyValueWrite(WRITE_BINARY);
646
647 if (_outputTail >= _outputEnd) {
648 _flushBuffer();
649 }
650 _outputBuffer[_outputTail++] = _quoteChar;
651 _writeBinary(b64variant, data, offset, offset+len);
652
653 if (_outputTail >= _outputEnd) {
654 _flushBuffer();
655 }
656 _outputBuffer[_outputTail++] = _quoteChar;
657 }
658
659 @Override
660 public int writeBinary(Base64Variant b64variant,
661 InputStream data, int dataLength)
662 throws IOException, JsonGenerationException
663 {
664 _verifyValueWrite(WRITE_BINARY);
665
666 if (_outputTail >= _outputEnd) {
667 _flushBuffer();
668 }
669 _outputBuffer[_outputTail++] = _quoteChar;
670 byte[] encodingBuffer = _ioContext.allocBase64Buffer();
671 int bytes;
672 try {
673 if (dataLength < 0) {
674 bytes = _writeBinary(b64variant, data, encodingBuffer);
675 } else {
676 int missing = _writeBinary(b64variant, data, encodingBuffer, dataLength);
677 if (missing > 0) {
678 _reportError("Too few bytes available: missing "+missing+" bytes (out of "+dataLength+")");
679 }
680 bytes = dataLength;
681 }
682 } finally {
683 _ioContext.releaseBase64Buffer(encodingBuffer);
684 }
685
686 if (_outputTail >= _outputEnd) {
687 _flushBuffer();
688 }
689 _outputBuffer[_outputTail++] = _quoteChar;
690 return bytes;
691 }
692
693
698
699 @Override
700 public void writeNumber(short s) throws IOException
701 {
702 _verifyValueWrite(WRITE_NUMBER);
703 if (_cfgNumbersAsStrings) {
704 _writeQuotedShort(s);
705 return;
706 }
707
708 if ((_outputTail + 6) >= _outputEnd) {
709 _flushBuffer();
710 }
711 _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
712 }
713
714 private void _writeQuotedShort(short s) throws IOException {
715 if ((_outputTail + 8) >= _outputEnd) {
716 _flushBuffer();
717 }
718 _outputBuffer[_outputTail++] = _quoteChar;
719 _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
720 _outputBuffer[_outputTail++] = _quoteChar;
721 }
722
723 @Override
724 public void writeNumber(int i) throws IOException
725 {
726 _verifyValueWrite(WRITE_NUMBER);
727 if (_cfgNumbersAsStrings) {
728 _writeQuotedInt(i);
729 return;
730 }
731
732 if ((_outputTail + 11) >= _outputEnd) {
733 _flushBuffer();
734 }
735 _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
736 }
737
738 private void _writeQuotedInt(int i) throws IOException {
739 if ((_outputTail + 13) >= _outputEnd) {
740 _flushBuffer();
741 }
742 _outputBuffer[_outputTail++] = _quoteChar;
743 _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
744 _outputBuffer[_outputTail++] = _quoteChar;
745 }
746
747 @Override
748 public void writeNumber(long l) throws IOException
749 {
750 _verifyValueWrite(WRITE_NUMBER);
751 if (_cfgNumbersAsStrings) {
752 _writeQuotedLong(l);
753 return;
754 }
755 if ((_outputTail + 21) >= _outputEnd) {
756
757 _flushBuffer();
758 }
759 _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
760 }
761
762 private void _writeQuotedLong(long l) throws IOException {
763 if ((_outputTail + 23) >= _outputEnd) {
764 _flushBuffer();
765 }
766 _outputBuffer[_outputTail++] = _quoteChar;
767 _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
768 _outputBuffer[_outputTail++] = _quoteChar;
769 }
770
771
772
773 @Override
774 public void writeNumber(BigInteger value) throws IOException
775 {
776 _verifyValueWrite(WRITE_NUMBER);
777 if (value == null) {
778 _writeNull();
779 } else if (_cfgNumbersAsStrings) {
780 _writeQuotedRaw(value.toString());
781 } else {
782 writeRaw(value.toString());
783 }
784 }
785
786 @SuppressWarnings("deprecation")
787 @Override
788 public void writeNumber(double d) throws IOException
789 {
790 if (_cfgNumbersAsStrings ||
791 (NumberOutput.notFinite(d) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS))) {
792 writeString(String.valueOf(d));
793 return;
794 }
795
796 _verifyValueWrite(WRITE_NUMBER);
797 writeRaw(String.valueOf(d));
798 }
799
800 @SuppressWarnings("deprecation")
801 @Override
802 public void writeNumber(float f) throws IOException
803 {
804 if (_cfgNumbersAsStrings ||
805 (NumberOutput.notFinite(f) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS))) {
806 writeString(String.valueOf(f));
807 return;
808 }
809
810 _verifyValueWrite(WRITE_NUMBER);
811 writeRaw(String.valueOf(f));
812 }
813
814 @Override
815 public void writeNumber(BigDecimal value) throws IOException
816 {
817
818 _verifyValueWrite(WRITE_NUMBER);
819 if (value == null) {
820 _writeNull();
821 } else if (_cfgNumbersAsStrings) {
822 _writeQuotedRaw(_asString(value));
823 } else {
824 writeRaw(_asString(value));
825 }
826 }
827
828 @Override
829 public void writeNumber(String encodedValue) throws IOException
830 {
831 _verifyValueWrite(WRITE_NUMBER);
832 if (_cfgNumbersAsStrings) {
833 _writeQuotedRaw(encodedValue);
834 } else {
835 writeRaw(encodedValue);
836 }
837 }
838
839 @Override
840 public void writeNumber(char[] encodedValueBuffer, int offset, int length) throws IOException {
841 _verifyValueWrite(WRITE_NUMBER);
842 if (_cfgNumbersAsStrings) {
843 _writeQuotedRaw(encodedValueBuffer, offset, length);
844 } else {
845 writeRaw(encodedValueBuffer, offset, length);
846 }
847 }
848
849 private void _writeQuotedRaw(String value) throws IOException
850 {
851 if (_outputTail >= _outputEnd) {
852 _flushBuffer();
853 }
854 _outputBuffer[_outputTail++] = _quoteChar;
855 writeRaw(value);
856 if (_outputTail >= _outputEnd) {
857 _flushBuffer();
858 }
859 _outputBuffer[_outputTail++] = _quoteChar;
860 }
861
862 private void _writeQuotedRaw(char[] text, int offset, int length) throws IOException
863 {
864 if (_outputTail >= _outputEnd) {
865 _flushBuffer();
866 }
867 _outputBuffer[_outputTail++] = _quoteChar;
868 writeRaw(text, offset, length);
869 if (_outputTail >= _outputEnd) {
870 _flushBuffer();
871 }
872 _outputBuffer[_outputTail++] = _quoteChar;
873 }
874
875 @Override
876 public void writeBoolean(boolean state) throws IOException
877 {
878 _verifyValueWrite(WRITE_BOOLEAN);
879 if ((_outputTail + 5) >= _outputEnd) {
880 _flushBuffer();
881 }
882 int ptr = _outputTail;
883 char[] buf = _outputBuffer;
884 if (state) {
885 buf[ptr] = 't';
886 buf[++ptr] = 'r';
887 buf[++ptr] = 'u';
888 buf[++ptr] = 'e';
889 } else {
890 buf[ptr] = 'f';
891 buf[++ptr] = 'a';
892 buf[++ptr] = 'l';
893 buf[++ptr] = 's';
894 buf[++ptr] = 'e';
895 }
896 _outputTail = ptr+1;
897 }
898
899 @Override
900 public void writeNull() throws IOException {
901 _verifyValueWrite(WRITE_NULL);
902 _writeNull();
903 }
904
905
910
911 @Override
912 protected final void _verifyValueWrite(String typeMsg) throws IOException
913 {
914 final int status = _writeContext.writeValue();
915 if (_cfgPrettyPrinter != null) {
916
917 _verifyPrettyValueWrite(typeMsg, status);
918 return;
919 }
920 char c;
921 switch (status) {
922 case JsonWriteContext.STATUS_OK_AS_IS:
923 default:
924 return;
925 case JsonWriteContext.STATUS_OK_AFTER_COMMA:
926 c = ',';
927 break;
928 case JsonWriteContext.STATUS_OK_AFTER_COLON:
929 c = ':';
930 break;
931 case JsonWriteContext.STATUS_OK_AFTER_SPACE:
932 if (_rootValueSeparator != null) {
933 writeRaw(_rootValueSeparator.getValue());
934 }
935 return;
936 case JsonWriteContext.STATUS_EXPECT_NAME:
937 _reportCantWriteValueExpectName(typeMsg);
938 return;
939 }
940 if (_outputTail >= _outputEnd) {
941 _flushBuffer();
942 }
943 _outputBuffer[_outputTail++] = c;
944 }
945
946
951
952 @Override
953 public void flush() throws IOException
954 {
955 _flushBuffer();
956 if (_writer != null) {
957 if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
958 _writer.flush();
959 }
960 }
961 }
962
963 @Override
964 public void close() throws IOException
965 {
966 super.close();
967
968
971
972 if (_outputBuffer != null
973 && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
974 while (true) {
975 JsonStreamContext ctxt = getOutputContext();
976 if (ctxt.inArray()) {
977 writeEndArray();
978 } else if (ctxt.inObject()) {
979 writeEndObject();
980 } else {
981 break;
982 }
983 }
984 }
985 _flushBuffer();
986 _outputHead = 0;
987 _outputTail = 0;
988
989
995 if (_writer != null) {
996 if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
997 _writer.close();
998 } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
999
1000 _writer.flush();
1001 }
1002 }
1003
1004 _releaseBuffers();
1005 }
1006
1007 @Override
1008 protected void _releaseBuffers()
1009 {
1010 char[] buf = _outputBuffer;
1011 if (buf != null) {
1012 _outputBuffer = null;
1013 _ioContext.releaseConcatBuffer(buf);
1014 }
1015 buf = _copyBuffer;
1016 if (buf != null) {
1017 _copyBuffer = null;
1018 _ioContext.releaseNameCopyBuffer(buf);
1019 }
1020 }
1021
1022
1027
1028 private void _writeString(String text) throws IOException
1029 {
1030
1035 final int len = text.length();
1036 if (len > _outputEnd) {
1037 _writeLongString(text);
1038 return;
1039 }
1040
1041
1042
1043 if ((_outputTail + len) > _outputEnd) {
1044 _flushBuffer();
1045 }
1046 text.getChars(0, len, _outputBuffer, _outputTail);
1047
1048 if (_characterEscapes != null) {
1049 _writeStringCustom(len);
1050 } else if (_maximumNonEscapedChar != 0) {
1051 _writeStringASCII(len, _maximumNonEscapedChar);
1052 } else {
1053 _writeString2(len);
1054 }
1055 }
1056
1057 private void _writeString2(final int len) throws IOException
1058 {
1059
1060 final int end = _outputTail + len;
1061 final int[] escCodes = _outputEscapes;
1062 final int escLen = escCodes.length;
1063
1064 output_loop:
1065 while (_outputTail < end) {
1066
1067 escape_loop:
1068 while (true) {
1069 char c = _outputBuffer[_outputTail];
1070 if (c < escLen && escCodes[c] != 0) {
1071 break escape_loop;
1072 }
1073 if (++_outputTail >= end) {
1074 break output_loop;
1075 }
1076 }
1077
1078
1079
1082 int flushLen = (_outputTail - _outputHead);
1083 if (flushLen > 0) {
1084 _writer.write(_outputBuffer, _outputHead, flushLen);
1085 }
1086
1089 char c = _outputBuffer[_outputTail++];
1090 _prependOrWriteCharacterEscape(c, escCodes[c]);
1091 }
1092 }
1093
1094
1098 private void _writeLongString(String text) throws IOException
1099 {
1100
1101 _flushBuffer();
1102
1103
1104 final int textLen = text.length();
1105 int offset = 0;
1106 do {
1107 int max = _outputEnd;
1108 int segmentLen = ((offset + max) > textLen)
1109 ? (textLen - offset) : max;
1110 text.getChars(offset, offset+segmentLen, _outputBuffer, 0);
1111 if (_characterEscapes != null) {
1112 _writeSegmentCustom(segmentLen);
1113 } else if (_maximumNonEscapedChar != 0) {
1114 _writeSegmentASCII(segmentLen, _maximumNonEscapedChar);
1115 } else {
1116 _writeSegment(segmentLen);
1117 }
1118 offset += segmentLen;
1119 } while (offset < textLen);
1120 }
1121
1122
1131 private void _writeSegment(int end) throws IOException
1132 {
1133 final int[] escCodes = _outputEscapes;
1134 final int escLen = escCodes.length;
1135
1136 int ptr = 0;
1137 int start = ptr;
1138
1139 output_loop:
1140 while (ptr < end) {
1141
1142 char c;
1143 while (true) {
1144 c = _outputBuffer[ptr];
1145 if (c < escLen && escCodes[c] != 0) {
1146 break;
1147 }
1148 if (++ptr >= end) {
1149 break;
1150 }
1151 }
1152
1153
1154
1157 int flushLen = (ptr - start);
1158 if (flushLen > 0) {
1159 _writer.write(_outputBuffer, start, flushLen);
1160 if (ptr >= end) {
1161 break output_loop;
1162 }
1163 }
1164 ++ptr;
1165
1166 start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCodes[c]);
1167 }
1168 }
1169
1170
1174 private void _writeString(char[] text, int offset, int len) throws IOException
1175 {
1176 if (_characterEscapes != null) {
1177 _writeStringCustom(text, offset, len);
1178 return;
1179 }
1180 if (_maximumNonEscapedChar != 0) {
1181 _writeStringASCII(text, offset, len, _maximumNonEscapedChar);
1182 return;
1183 }
1184
1185
1186
1187
1188 len += offset;
1189 final int[] escCodes = _outputEscapes;
1190 final int escLen = escCodes.length;
1191 while (offset < len) {
1192 int start = offset;
1193
1194 while (true) {
1195 char c = text[offset];
1196 if (c < escLen && escCodes[c] != 0) {
1197 break;
1198 }
1199 if (++offset >= len) {
1200 break;
1201 }
1202 }
1203
1204
1205 int newAmount = offset - start;
1206 if (newAmount < SHORT_WRITE) {
1207
1208 if ((_outputTail + newAmount) > _outputEnd) {
1209 _flushBuffer();
1210 }
1211 if (newAmount > 0) {
1212 System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
1213 _outputTail += newAmount;
1214 }
1215 } else {
1216 _flushBuffer();
1217 _writer.write(text, start, newAmount);
1218 }
1219
1220 if (offset >= len) {
1221 break;
1222 }
1223
1224 char c = text[offset++];
1225 _appendCharacterEscape(c, escCodes[c]);
1226 }
1227 }
1228
1229
1235
1236
1239 private void _writeStringASCII(final int len, final int maxNonEscaped)
1240 throws IOException, JsonGenerationException
1241 {
1242
1243 int end = _outputTail + len;
1244 final int[] escCodes = _outputEscapes;
1245 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1246 int escCode = 0;
1247
1248 output_loop:
1249 while (_outputTail < end) {
1250 char c;
1251
1252 escape_loop:
1253 while (true) {
1254 c = _outputBuffer[_outputTail];
1255 if (c < escLimit) {
1256 escCode = escCodes[c];
1257 if (escCode != 0) {
1258 break escape_loop;
1259 }
1260 } else if (c > maxNonEscaped) {
1261 escCode = CharacterEscapes.ESCAPE_STANDARD;
1262 break escape_loop;
1263 }
1264 if (++_outputTail >= end) {
1265 break output_loop;
1266 }
1267 }
1268 int flushLen = (_outputTail - _outputHead);
1269 if (flushLen > 0) {
1270 _writer.write(_outputBuffer, _outputHead, flushLen);
1271 }
1272 ++_outputTail;
1273 _prependOrWriteCharacterEscape(c, escCode);
1274 }
1275 }
1276
1277 private void _writeSegmentASCII(int end, final int maxNonEscaped)
1278 throws IOException, JsonGenerationException
1279 {
1280 final int[] escCodes = _outputEscapes;
1281 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1282
1283 int ptr = 0;
1284 int escCode = 0;
1285 int start = ptr;
1286
1287 output_loop:
1288 while (ptr < end) {
1289
1290 char c;
1291 while (true) {
1292 c = _outputBuffer[ptr];
1293 if (c < escLimit) {
1294 escCode = escCodes[c];
1295 if (escCode != 0) {
1296 break;
1297 }
1298 } else if (c > maxNonEscaped) {
1299 escCode = CharacterEscapes.ESCAPE_STANDARD;
1300 break;
1301 }
1302 if (++ptr >= end) {
1303 break;
1304 }
1305 }
1306 int flushLen = (ptr - start);
1307 if (flushLen > 0) {
1308 _writer.write(_outputBuffer, start, flushLen);
1309 if (ptr >= end) {
1310 break output_loop;
1311 }
1312 }
1313 ++ptr;
1314 start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
1315 }
1316 }
1317
1318 private void _writeStringASCII(char[] text, int offset, int len,
1319 final int maxNonEscaped)
1320 throws IOException, JsonGenerationException
1321 {
1322 len += offset;
1323 final int[] escCodes = _outputEscapes;
1324 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1325
1326 int escCode = 0;
1327
1328 while (offset < len) {
1329 int start = offset;
1330 char c;
1331
1332 while (true) {
1333 c = text[offset];
1334 if (c < escLimit) {
1335 escCode = escCodes[c];
1336 if (escCode != 0) {
1337 break;
1338 }
1339 } else if (c > maxNonEscaped) {
1340 escCode = CharacterEscapes.ESCAPE_STANDARD;
1341 break;
1342 }
1343 if (++offset >= len) {
1344 break;
1345 }
1346 }
1347
1348
1349 int newAmount = offset - start;
1350 if (newAmount < SHORT_WRITE) {
1351
1352 if ((_outputTail + newAmount) > _outputEnd) {
1353 _flushBuffer();
1354 }
1355 if (newAmount > 0) {
1356 System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
1357 _outputTail += newAmount;
1358 }
1359 } else {
1360 _flushBuffer();
1361 _writer.write(text, start, newAmount);
1362 }
1363
1364 if (offset >= len) {
1365 break;
1366 }
1367
1368 ++offset;
1369 _appendCharacterEscape(c, escCode);
1370 }
1371 }
1372
1373
1379
1380
1383 private void _writeStringCustom(final int len)
1384 throws IOException, JsonGenerationException
1385 {
1386
1387 int end = _outputTail + len;
1388 final int[] escCodes = _outputEscapes;
1389 final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
1390 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1391 int escCode = 0;
1392 final CharacterEscapes customEscapes = _characterEscapes;
1393
1394 output_loop:
1395 while (_outputTail < end) {
1396 char c;
1397
1398 escape_loop:
1399 while (true) {
1400 c = _outputBuffer[_outputTail];
1401 if (c < escLimit) {
1402 escCode = escCodes[c];
1403 if (escCode != 0) {
1404 break escape_loop;
1405 }
1406 } else if (c > maxNonEscaped) {
1407 escCode = CharacterEscapes.ESCAPE_STANDARD;
1408 break escape_loop;
1409 } else {
1410 if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
1411 escCode = CharacterEscapes.ESCAPE_CUSTOM;
1412 break escape_loop;
1413 }
1414 }
1415 if (++_outputTail >= end) {
1416 break output_loop;
1417 }
1418 }
1419 int flushLen = (_outputTail - _outputHead);
1420 if (flushLen > 0) {
1421 _writer.write(_outputBuffer, _outputHead, flushLen);
1422 }
1423 ++_outputTail;
1424 _prependOrWriteCharacterEscape(c, escCode);
1425 }
1426 }
1427
1428 private void _writeSegmentCustom(int end)
1429 throws IOException, JsonGenerationException
1430 {
1431 final int[] escCodes = _outputEscapes;
1432 final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
1433 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1434 final CharacterEscapes customEscapes = _characterEscapes;
1435
1436 int ptr = 0;
1437 int escCode = 0;
1438 int start = ptr;
1439
1440 output_loop:
1441 while (ptr < end) {
1442
1443 char c;
1444 while (true) {
1445 c = _outputBuffer[ptr];
1446 if (c < escLimit) {
1447 escCode = escCodes[c];
1448 if (escCode != 0) {
1449 break;
1450 }
1451 } else if (c > maxNonEscaped) {
1452 escCode = CharacterEscapes.ESCAPE_STANDARD;
1453 break;
1454 } else {
1455 if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
1456 escCode = CharacterEscapes.ESCAPE_CUSTOM;
1457 break;
1458 }
1459 }
1460 if (++ptr >= end) {
1461 break;
1462 }
1463 }
1464 int flushLen = (ptr - start);
1465 if (flushLen > 0) {
1466 _writer.write(_outputBuffer, start, flushLen);
1467 if (ptr >= end) {
1468 break output_loop;
1469 }
1470 }
1471 ++ptr;
1472 start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
1473 }
1474 }
1475
1476 private void _writeStringCustom(char[] text, int offset, int len)
1477 throws IOException, JsonGenerationException
1478 {
1479 len += offset;
1480 final int[] escCodes = _outputEscapes;
1481 final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
1482 final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
1483 final CharacterEscapes customEscapes = _characterEscapes;
1484
1485 int escCode = 0;
1486
1487 while (offset < len) {
1488 int start = offset;
1489 char c;
1490
1491 while (true) {
1492 c = text[offset];
1493 if (c < escLimit) {
1494 escCode = escCodes[c];
1495 if (escCode != 0) {
1496 break;
1497 }
1498 } else if (c > maxNonEscaped) {
1499 escCode = CharacterEscapes.ESCAPE_STANDARD;
1500 break;
1501 } else {
1502 if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
1503 escCode = CharacterEscapes.ESCAPE_CUSTOM;
1504 break;
1505 }
1506 }
1507 if (++offset >= len) {
1508 break;
1509 }
1510 }
1511
1512
1513 int newAmount = offset - start;
1514 if (newAmount < SHORT_WRITE) {
1515
1516 if ((_outputTail + newAmount) > _outputEnd) {
1517 _flushBuffer();
1518 }
1519 if (newAmount > 0) {
1520 System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
1521 _outputTail += newAmount;
1522 }
1523 } else {
1524 _flushBuffer();
1525 _writer.write(text, start, newAmount);
1526 }
1527
1528 if (offset >= len) {
1529 break;
1530 }
1531
1532 ++offset;
1533 _appendCharacterEscape(c, escCode);
1534 }
1535 }
1536
1537
1542
1543 protected final void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd)
1544 throws IOException, JsonGenerationException
1545 {
1546
1547 int safeInputEnd = inputEnd - 3;
1548
1549 int safeOutputEnd = _outputEnd - 6;
1550 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1551
1552
1553 while (inputPtr <= safeInputEnd) {
1554 if (_outputTail > safeOutputEnd) {
1555 _flushBuffer();
1556 }
1557
1558 int b24 = ((int) input[inputPtr++]) << 8;
1559 b24 |= ((int) input[inputPtr++]) & 0xFF;
1560 b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
1561 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1562 if (--chunksBeforeLF <= 0) {
1563
1564 _outputBuffer[_outputTail++] = '\\';
1565 _outputBuffer[_outputTail++] = 'n';
1566 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1567 }
1568 }
1569
1570
1571 int inputLeft = inputEnd - inputPtr;
1572 if (inputLeft > 0) {
1573 if (_outputTail > safeOutputEnd) {
1574 _flushBuffer();
1575 }
1576 int b24 = ((int) input[inputPtr++]) << 16;
1577 if (inputLeft == 2) {
1578 b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
1579 }
1580 _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
1581 }
1582 }
1583
1584
1585 protected final int _writeBinary(Base64Variant b64variant,
1586 InputStream data, byte[] readBuffer, int bytesLeft)
1587 throws IOException, JsonGenerationException
1588 {
1589 int inputPtr = 0;
1590 int inputEnd = 0;
1591 int lastFullOffset = -3;
1592
1593
1594 int safeOutputEnd = _outputEnd - 6;
1595 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1596
1597 while (bytesLeft > 2) {
1598 if (inputPtr > lastFullOffset) {
1599 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
1600 inputPtr = 0;
1601 if (inputEnd < 3) {
1602 break;
1603 }
1604 lastFullOffset = inputEnd-3;
1605 }
1606 if (_outputTail > safeOutputEnd) {
1607 _flushBuffer();
1608 }
1609 int b24 = ((int) readBuffer[inputPtr++]) << 8;
1610 b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
1611 b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
1612 bytesLeft -= 3;
1613 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1614 if (--chunksBeforeLF <= 0) {
1615 _outputBuffer[_outputTail++] = '\\';
1616 _outputBuffer[_outputTail++] = 'n';
1617 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1618 }
1619 }
1620
1621
1622 if (bytesLeft > 0) {
1623 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
1624 inputPtr = 0;
1625 if (inputEnd > 0) {
1626 if (_outputTail > safeOutputEnd) {
1627 _flushBuffer();
1628 }
1629 int b24 = ((int) readBuffer[inputPtr++]) << 16;
1630 int amount;
1631 if (inputPtr < inputEnd) {
1632 b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
1633 amount = 2;
1634 } else {
1635 amount = 1;
1636 }
1637 _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
1638 bytesLeft -= amount;
1639 }
1640 }
1641 return bytesLeft;
1642 }
1643
1644
1645 protected final int _writeBinary(Base64Variant b64variant,
1646 InputStream data, byte[] readBuffer)
1647 throws IOException, JsonGenerationException
1648 {
1649 int inputPtr = 0;
1650 int inputEnd = 0;
1651 int lastFullOffset = -3;
1652 int bytesDone = 0;
1653
1654
1655 int safeOutputEnd = _outputEnd - 6;
1656 int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1657
1658
1659 while (true) {
1660 if (inputPtr > lastFullOffset) {
1661 inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
1662 inputPtr = 0;
1663 if (inputEnd < 3) {
1664 break;
1665 }
1666 lastFullOffset = inputEnd-3;
1667 }
1668 if (_outputTail > safeOutputEnd) {
1669 _flushBuffer();
1670 }
1671
1672 int b24 = ((int) readBuffer[inputPtr++]) << 8;
1673 b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
1674 b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
1675 bytesDone += 3;
1676 _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
1677 if (--chunksBeforeLF <= 0) {
1678 _outputBuffer[_outputTail++] = '\\';
1679 _outputBuffer[_outputTail++] = 'n';
1680 chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
1681 }
1682 }
1683
1684
1685 if (inputPtr < inputEnd) {
1686 if (_outputTail > safeOutputEnd) {
1687 _flushBuffer();
1688 }
1689 int b24 = ((int) readBuffer[inputPtr++]) << 16;
1690 int amount = 1;
1691 if (inputPtr < inputEnd) {
1692 b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
1693 amount = 2;
1694 }
1695 bytesDone += amount;
1696 _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
1697 }
1698 return bytesDone;
1699 }
1700
1701 private int _readMore(InputStream in,
1702 byte[] readBuffer, int inputPtr, int inputEnd,
1703 int maxRead) throws IOException
1704 {
1705
1706 int i = 0;
1707 while (inputPtr < inputEnd) {
1708 readBuffer[i++] = readBuffer[inputPtr++];
1709 }
1710 inputPtr = 0;
1711 inputEnd = i;
1712 maxRead = Math.min(maxRead, readBuffer.length);
1713
1714 do {
1715 int length = maxRead - inputEnd;
1716 if (length == 0) {
1717 break;
1718 }
1719 int count = in.read(readBuffer, inputEnd, length);
1720 if (count < 0) {
1721 return inputEnd;
1722 }
1723 inputEnd += count;
1724 } while (inputEnd < 3);
1725 return inputEnd;
1726 }
1727
1728
1733
1734 private final void _writeNull() throws IOException
1735 {
1736 if ((_outputTail + 4) >= _outputEnd) {
1737 _flushBuffer();
1738 }
1739 int ptr = _outputTail;
1740 char[] buf = _outputBuffer;
1741 buf[ptr] = 'n';
1742 buf[++ptr] = 'u';
1743 buf[++ptr] = 'l';
1744 buf[++ptr] = 'l';
1745 _outputTail = ptr+1;
1746 }
1747
1748
1753
1754
1759 private void _prependOrWriteCharacterEscape(char ch, int escCode)
1760 throws IOException, JsonGenerationException
1761 {
1762 if (escCode >= 0) {
1763 if (_outputTail >= 2) {
1764 int ptr = _outputTail - 2;
1765 _outputHead = ptr;
1766 _outputBuffer[ptr++] = '\\';
1767 _outputBuffer[ptr] = (char) escCode;
1768 return;
1769 }
1770
1771 char[] buf = _entityBuffer;
1772 if (buf == null) {
1773 buf = _allocateEntityBuffer();
1774 }
1775 _outputHead = _outputTail;
1776 buf[1] = (char) escCode;
1777 _writer.write(buf, 0, 2);
1778 return;
1779 }
1780 if (escCode != CharacterEscapes.ESCAPE_CUSTOM) {
1781 if (_outputTail >= 6) {
1782 char[] buf = _outputBuffer;
1783 int ptr = _outputTail - 6;
1784 _outputHead = ptr;
1785 buf[ptr] = '\\';
1786 buf[++ptr] = 'u';
1787
1788 if (ch > 0xFF) {
1789 int hi = (ch >> 8) & 0xFF;
1790 buf[++ptr] = HEX_CHARS[hi >> 4];
1791 buf[++ptr] = HEX_CHARS[hi & 0xF];
1792 ch &= 0xFF;
1793 } else {
1794 buf[++ptr] = '0';
1795 buf[++ptr] = '0';
1796 }
1797 buf[++ptr] = HEX_CHARS[ch >> 4];
1798 buf[++ptr] = HEX_CHARS[ch & 0xF];
1799 return;
1800 }
1801
1802 char[] buf = _entityBuffer;
1803 if (buf == null) {
1804 buf = _allocateEntityBuffer();
1805 }
1806 _outputHead = _outputTail;
1807 if (ch > 0xFF) {
1808 int hi = (ch >> 8) & 0xFF;
1809 int lo = ch & 0xFF;
1810 buf[10] = HEX_CHARS[hi >> 4];
1811 buf[11] = HEX_CHARS[hi & 0xF];
1812 buf[12] = HEX_CHARS[lo >> 4];
1813 buf[13] = HEX_CHARS[lo & 0xF];
1814 _writer.write(buf, 8, 6);
1815 } else {
1816 buf[6] = HEX_CHARS[ch >> 4];
1817 buf[7] = HEX_CHARS[ch & 0xF];
1818 _writer.write(buf, 2, 6);
1819 }
1820 return;
1821 }
1822 String escape;
1823
1824 if (_currentEscape == null) {
1825 escape = _characterEscapes.getEscapeSequence(ch).getValue();
1826 } else {
1827 escape = _currentEscape.getValue();
1828 _currentEscape = null;
1829 }
1830 int len = escape.length();
1831 if (_outputTail >= len) {
1832 int ptr = _outputTail - len;
1833 _outputHead = ptr;
1834 escape.getChars(0, len, _outputBuffer, ptr);
1835 return;
1836 }
1837
1838 _outputHead = _outputTail;
1839 _writer.write(escape);
1840 }
1841
1842
1849 private int _prependOrWriteCharacterEscape(char[] buffer, int ptr, int end,
1850 char ch, int escCode)
1851 throws IOException, JsonGenerationException
1852 {
1853 if (escCode >= 0) {
1854 if (ptr > 1 && ptr < end) {
1855 ptr -= 2;
1856 buffer[ptr] = '\\';
1857 buffer[ptr+1] = (char) escCode;
1858 } else {
1859 char[] ent = _entityBuffer;
1860 if (ent == null) {
1861 ent = _allocateEntityBuffer();
1862 }
1863 ent[1] = (char) escCode;
1864 _writer.write(ent, 0, 2);
1865 }
1866 return ptr;
1867 }
1868 if (escCode != CharacterEscapes.ESCAPE_CUSTOM) {
1869 if (ptr > 5 && ptr < end) {
1870 ptr -= 6;
1871 buffer[ptr++] = '\\';
1872 buffer[ptr++] = 'u';
1873
1874 if (ch > 0xFF) {
1875 int hi = (ch >> 8) & 0xFF;
1876 buffer[ptr++] = HEX_CHARS[hi >> 4];
1877 buffer[ptr++] = HEX_CHARS[hi & 0xF];
1878 ch &= 0xFF;
1879 } else {
1880 buffer[ptr++] = '0';
1881 buffer[ptr++] = '0';
1882 }
1883 buffer[ptr++] = HEX_CHARS[ch >> 4];
1884 buffer[ptr] = HEX_CHARS[ch & 0xF];
1885 ptr -= 5;
1886 } else {
1887
1888 char[] ent = _entityBuffer;
1889 if (ent == null) {
1890 ent = _allocateEntityBuffer();
1891 }
1892 _outputHead = _outputTail;
1893 if (ch > 0xFF) {
1894 int hi = (ch >> 8) & 0xFF;
1895 int lo = ch & 0xFF;
1896 ent[10] = HEX_CHARS[hi >> 4];
1897 ent[11] = HEX_CHARS[hi & 0xF];
1898 ent[12] = HEX_CHARS[lo >> 4];
1899 ent[13] = HEX_CHARS[lo & 0xF];
1900 _writer.write(ent, 8, 6);
1901 } else {
1902 ent[6] = HEX_CHARS[ch >> 4];
1903 ent[7] = HEX_CHARS[ch & 0xF];
1904 _writer.write(ent, 2, 6);
1905 }
1906 }
1907 return ptr;
1908 }
1909 String escape;
1910 if (_currentEscape == null) {
1911 escape = _characterEscapes.getEscapeSequence(ch).getValue();
1912 } else {
1913 escape = _currentEscape.getValue();
1914 _currentEscape = null;
1915 }
1916 int len = escape.length();
1917 if (ptr >= len && ptr < end) {
1918 ptr -= len;
1919 escape.getChars(0, len, buffer, ptr);
1920 } else {
1921 _writer.write(escape);
1922 }
1923 return ptr;
1924 }
1925
1926
1930 private void _appendCharacterEscape(char ch, int escCode)
1931 throws IOException, JsonGenerationException
1932 {
1933 if (escCode >= 0) {
1934 if ((_outputTail + 2) > _outputEnd) {
1935 _flushBuffer();
1936 }
1937 _outputBuffer[_outputTail++] = '\\';
1938 _outputBuffer[_outputTail++] = (char) escCode;
1939 return;
1940 }
1941 if (escCode != CharacterEscapes.ESCAPE_CUSTOM) {
1942 if ((_outputTail + 5) >= _outputEnd) {
1943 _flushBuffer();
1944 }
1945 int ptr = _outputTail;
1946 char[] buf = _outputBuffer;
1947 buf[ptr++] = '\\';
1948 buf[ptr++] = 'u';
1949
1950 if (ch > 0xFF) {
1951 int hi = (ch >> 8) & 0xFF;
1952 buf[ptr++] = HEX_CHARS[hi >> 4];
1953 buf[ptr++] = HEX_CHARS[hi & 0xF];
1954 ch &= 0xFF;
1955 } else {
1956 buf[ptr++] = '0';
1957 buf[ptr++] = '0';
1958 }
1959 buf[ptr++] = HEX_CHARS[ch >> 4];
1960 buf[ptr++] = HEX_CHARS[ch & 0xF];
1961 _outputTail = ptr;
1962 return;
1963 }
1964 String escape;
1965 if (_currentEscape == null) {
1966 escape = _characterEscapes.getEscapeSequence(ch).getValue();
1967 } else {
1968 escape = _currentEscape.getValue();
1969 _currentEscape = null;
1970 }
1971 int len = escape.length();
1972 if ((_outputTail + len) > _outputEnd) {
1973 _flushBuffer();
1974 if (len > _outputEnd) {
1975 _writer.write(escape);
1976 return;
1977 }
1978 }
1979 escape.getChars(0, len, _outputBuffer, _outputTail);
1980 _outputTail += len;
1981 }
1982
1983 private char[] _allocateEntityBuffer()
1984 {
1985 char[] buf = new char[14];
1986
1987 buf[0] = '\\';
1988
1989 buf[2] = '\\';
1990 buf[3] = 'u';
1991 buf[4] = '0';
1992 buf[5] = '0';
1993
1994 buf[8] = '\\';
1995 buf[9] = 'u';
1996 _entityBuffer = buf;
1997 return buf;
1998 }
1999
2000
2003 private char[] _allocateCopyBuffer() {
2004 if (_copyBuffer == null) {
2005 _copyBuffer = _ioContext.allocNameCopyBuffer(2000);
2006 }
2007 return _copyBuffer;
2008 }
2009
2010 protected void _flushBuffer() throws IOException
2011 {
2012 int len = _outputTail - _outputHead;
2013 if (len > 0) {
2014 int offset = _outputHead;
2015 _outputTail = _outputHead = 0;
2016 _writer.write(_outputBuffer, offset, len);
2017 }
2018 }
2019 }
2020