protected final void _flushBuffer() throws IOException {
   int len = _outputTail - _outputHead;
   if (len > 0) {
     int offset = _outputHead;
     _outputTail = _outputHead = 0;
     _writer.write(_outputBuffer, offset, len);
   }
 }
  /**
   * @param escCode Character code for escape sequence (\C); or -1 to indicate a generic (\\uXXXX)
   *     sequence.
   */
  private void _writeSingleEscape(int escCode) throws IOException {
    char[] buf = _entityBuffer;
    if (buf == null) {
      buf = new char[6];
      buf[0] = '\\';
      buf[2] = '0';
      buf[3] = '0';
    }

    if (escCode < 0) { // control char, value -(char + 1)
      int value = -(escCode + 1);
      buf[1] = 'u';
      // We know it's a control char, so only the last 2 chars are non-0
      buf[4] = HEX_CHARS[value >> 4];
      buf[5] = HEX_CHARS[value & 0xF];
      _writer.write(buf, 0, 6);
    } else {
      buf[1] = (char) escCode;
      _writer.write(buf, 0, 2);
    }
  }
  /**
   * This method called when the string content is already in a char buffer, and need not be copied
   * for processing.
   */
  private void _writeString(char[] text, int offset, int len)
      throws IOException, JsonGenerationException {
    /* Let's just find longest spans of non-escapable
     * content, and for each see if it makes sense
     * to copy them, or write through
     */
    len += offset; // -> len marks the end from now on
    final int[] escCodes = CharTypes.getOutputEscapes();
    final int escLen = escCodes.length;
    while (offset < len) {
      int start = offset;

      while (true) {
        char c = text[offset];
        if (c < escLen && escCodes[c] != 0) {
          break;
        }
        if (++offset >= len) {
          break;
        }
      }

      // Short span? Better just copy it to buffer first:
      int newAmount = offset - start;
      if (newAmount < SHORT_WRITE) {
        // Note: let's reserve room for escaped char (up to 6 chars)
        if ((_outputTail + newAmount) > _outputEnd) {
          _flushBuffer();
        }
        if (newAmount > 0) {
          System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
          _outputTail += newAmount;
        }
      } else { // Nope: better just write through
        _flushBuffer();
        _writer.write(text, start, newAmount);
      }
      // Was this the end?
      if (offset >= len) { // yup
        break;
      }
      // Nope, need to escape the char.
      int escCode = escCodes[text[offset]];
      ++offset;
      int needLen = (escCode < 0) ? 6 : 2;
      if ((_outputTail + needLen) > _outputEnd) {
        _flushBuffer();
      }
      _appendSingleEscape(escCode, _outputBuffer, _outputTail);
      _outputTail += needLen;
    }
  }
  /**
   * Method called to output textual context which has been copied to the output buffer prior to
   * call. If any escaping is needed, it will also be handled by the method.
   *
   * <p>Note: when called, textual content to write is within output buffer, right after buffered
   * content (if any). That's why only length of that text is passed, as buffer and offset are
   * implied.
   */
  private final void _writeSegment(int end) throws IOException, JsonGenerationException {
    final int[] escCodes = CharTypes.getOutputEscapes();
    final int escLen = escCodes.length;

    int ptr = 0;

    output_loop:
    while (ptr < end) {
      // Fast loop for chars not needing escaping
      int start = ptr;
      while (true) {
        char c = _outputBuffer[ptr];
        if (c < escLen && escCodes[c] != 0) {
          break;
        }
        if (++ptr >= end) {
          break;
        }
      }

      // Ok, bumped into something that needs escaping.
      /* First things first: need to flush the buffer.
       * Inlined, as we don't want to lose tail pointer
       */
      int flushLen = (ptr - start);
      if (flushLen > 0) {
        _writer.write(_outputBuffer, start, flushLen);
        if (ptr >= end) {
          break output_loop;
        }
      }
      /* In any case, tail will be the new start, so hopefully
       * we have room now.
       */
      {
        int escCode = escCodes[_outputBuffer[ptr]];
        ++ptr;
        int needLen = (escCode < 0) ? 6 : 2;
        // If not, need to call separate method (note: buffer is empty now)
        if (needLen > _outputTail) {
          _writeSingleEscape(escCode);
        } else {
          // But if it fits, can just prepend to buffer
          ptr -= needLen;
          _appendSingleEscape(escCode, _outputBuffer, ptr);
        }
      }
    }
  }
 public void writeRaw(char[] text, int offset, int len)
     throws IOException, JsonGenerationException {
   // Only worth buffering if it's a short write?
   if (len < SHORT_WRITE) {
     int room = _outputEnd - _outputTail;
     if (len > room) {
       _flushBuffer();
     }
     System.arraycopy(text, offset, _outputBuffer, _outputTail, len);
     _outputTail += len;
     return;
   }
   // Otherwise, better just pass through:
   _flushBuffer();
   _writer.write(text, offset, len);
 }
  private void _writeString(String text) throws IOException, JsonGenerationException {
    /* One check first: if String won't fit in the buffer, let's
     * segment writes. No point in extending buffer to huge sizes
     * (like if someone wants to include multi-megabyte base64
     * encoded stuff or such)
     */
    int len = text.length();
    if (len > _outputEnd) { // Let's reserve space for entity at begin/end
      _writeLongString(text);
      return;
    }

    // Ok: we know String will fit in buffer ok
    // But do we need to flush first?
    if ((_outputTail + len) > _outputEnd) {
      _flushBuffer();
    }
    text.getChars(0, len, _outputBuffer, _outputTail);

    // And then we'll need to verify need for escaping etc:
    int end = _outputTail + len;
    final int[] escCodes = CharTypes.getOutputEscapes();
    final int escLen = escCodes.length;

    output_loop:
    while (_outputTail < end) {
      // Fast loop for chars not needing escaping
      escape_loop:
      while (true) {
        char c = _outputBuffer[_outputTail];
        if (c < escLen && escCodes[c] != 0) {
          break escape_loop;
        }
        if (++_outputTail >= end) {
          break output_loop;
        }
      }

      // Ok, bumped into something that needs escaping.
      /* First things first: need to flush the buffer.
       * Inlined, as we don't want to lose tail pointer
       */
      int flushLen = (_outputTail - _outputHead);
      if (flushLen > 0) {
        _writer.write(_outputBuffer, _outputHead, flushLen);
      }
      /* In any case, tail will be the new start, so hopefully
       * we have room now.
       */
      {
        int escCode = escCodes[_outputBuffer[_outputTail]];
        ++_outputTail;
        int needLen = (escCode < 0) ? 6 : 2;
        // If not, need to call separate method (note: buffer is empty now)
        if (needLen > _outputTail) {
          _outputHead = _outputTail;
          _writeSingleEscape(escCode);
        } else {
          // But if it fits, can just prepend to buffer
          int ptr = _outputTail - needLen;
          _outputHead = ptr;
          _appendSingleEscape(escCode, _outputBuffer, ptr);
        }
      }
    }
  }