//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.server;

import java.io.IOException;

OutputWriter. A writer that can wrap a HttpOutput stream and provide character encodings. The UTF-8 encoding is done by this class and no additional buffers or Writers are used. The UTF-8 code was inspired by http://javolution.org
/** * OutputWriter. * A writer that can wrap a {@link HttpOutput} stream and provide * character encodings. * * The UTF-8 encoding is done by this class and no additional * buffers or Writers are used. * The UTF-8 code was inspired by http://javolution.org */
public class Utf8HttpWriter extends HttpWriter { int _surrogate = 0; public Utf8HttpWriter(HttpOutput out) { super(out); } @Override public void write(char[] s, int offset, int length) throws IOException { HttpOutput out = _out; while (length > 0) { _bytes.reset(); int chars = Math.min(length, MAX_OUTPUT_CHARS); byte[] buffer = _bytes.getBuf(); int bytes = _bytes.getCount(); if (bytes + chars > buffer.length) chars = buffer.length - bytes; for (int i = 0; i < chars; i++) { int code = s[offset + i]; // Do we already have a surrogate? if (_surrogate == 0) { // No - is this char code a surrogate? if (Character.isHighSurrogate((char)code)) { _surrogate = code; // UCS-? continue; } } // else handle a low surrogate else if (Character.isLowSurrogate((char)code)) { code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4 } // else UCS-2 else { code = _surrogate; // UCS-2 _surrogate = 0; // USED i--; } if ((code & 0xffffff80) == 0) { // 1b if (bytes >= buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(code); } else { if ((code & 0xfffff800) == 0) { // 2b if (bytes + 2 > buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(0xc0 | (code >> 6)); buffer[bytes++] = (byte)(0x80 | (code & 0x3f)); } else if ((code & 0xffff0000) == 0) { // 3b if (bytes + 3 > buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(0xe0 | (code >> 12)); buffer[bytes++] = (byte)(0x80 | ((code >> 6) & 0x3f)); buffer[bytes++] = (byte)(0x80 | (code & 0x3f)); } else if ((code & 0xff200000) == 0) { // 4b if (bytes + 4 > buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(0xf0 | (code >> 18)); buffer[bytes++] = (byte)(0x80 | ((code >> 12) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 6) & 0x3f)); buffer[bytes++] = (byte)(0x80 | (code & 0x3f)); } else if ((code & 0xf4000000) == 0) { // 5b if (bytes + 5 > buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(0xf8 | (code >> 24)); buffer[bytes++] = (byte)(0x80 | ((code >> 18) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 12) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 6) & 0x3f)); buffer[bytes++] = (byte)(0x80 | (code & 0x3f)); } else if ((code & 0x80000000) == 0) { // 6b if (bytes + 6 > buffer.length) { chars = i; break; } buffer[bytes++] = (byte)(0xfc | (code >> 30)); buffer[bytes++] = (byte)(0x80 | ((code >> 24) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 18) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 12) & 0x3f)); buffer[bytes++] = (byte)(0x80 | ((code >> 6) & 0x3f)); buffer[bytes++] = (byte)(0x80 | (code & 0x3f)); } else { buffer[bytes++] = (byte)('?'); } _surrogate = 0; // USED if (bytes == buffer.length) { chars = i + 1; break; } } } _bytes.setCount(bytes); _bytes.writeTo(out); length -= chars; offset += chars; } } }