blob: ae878d25821dd1ebbd8e0d95282dc361d8ddd240 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server;
import java.io.IOException;
/** 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;
if (length==0 && out.isAllContentWritten())
{
close();
return;
}
while (length > 0)
{
_bytes.reset();
int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
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;
}
}
}