content: /*
   * Copyright (c) 2010-2019 Nathan Rajlich
   *
   *  Permission is hereby granted, free of charge, to any person
   *  obtaining a copy of this software and associated documentation
   *  files (the "Software"), to deal in the Software without
   *  restriction, including without limitation the rights to use,
   *  copy, modify, merge, publish, distribute, sublicense, and/or sell
   *  copies of the Software, and to permit persons to whom the
   *  Software is furnished to do so, subject to the following
   *  conditions:
   *
   *  The above copyright notice and this permission notice shall be
   *  included in all copies or substantial portions of the Software.
   *
   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   *  OTHER DEALINGS IN THE SOFTWARE.
   */
  
  package com.youku.ribut.core.socket.java_websocket.util;
  
  import com.youku.ribut.core.socket.java_websocket.exceptions.InvalidDataException;
  import com.youku.ribut.core.socket.java_websocket.exceptions.InvalidEncodingException;
  import com.youku.ribut.core.socket.java_websocket.framing.CloseFrame;
  
  import java.io.UnsupportedEncodingException;
  import java.nio.ByteBuffer;
  import java.nio.charset.CharacterCodingException;
  import java.nio.charset.Charset;
  import java.nio.charset.CharsetDecoder;
  import java.nio.charset.CodingErrorAction;
  
  public class Charsetfunctions {
  
  	/**
  	 * Private constructor for real static class
  	 */
  	private Charsetfunctions() {}
  
  	private static final CodingErrorAction codingErrorAction = CodingErrorAction.REPORT;
  
  	/*
  	* @return UTF-8 encoding in bytes
  	*/
  	public static byte[] utf8Bytes( String s ) {
  		try {
  			return s.getBytes( "UTF8" );
  		} catch ( UnsupportedEncodingException e ) {
  			throw new InvalidEncodingException( e );
  		}
  	}
  
  	/*
  	* @return ASCII encoding in bytes
  	*/
  	public static byte[] asciiBytes( String s ) {
  		try {
  			return s.getBytes( "ASCII" );
  		} catch ( UnsupportedEncodingException e ) {
  			throw new InvalidEncodingException( e );
  		}
  	}
  
  	public static String stringAscii( byte[] bytes ) {
  		return stringAscii( bytes, 0, bytes.length );
  	}
  
  	public static String stringAscii( byte[] bytes, int offset, int length ) {
  		try {
  			return new String( bytes, offset, length, "ASCII" );
  		} catch ( UnsupportedEncodingException e ) {
  			throw new InvalidEncodingException( e );
  		}
  	}
  
  	public static String stringUtf8( byte[] bytes ) throws InvalidDataException {
  		return stringUtf8( ByteBuffer.wrap( bytes ) );
  	}
  
  	public static String stringUtf8( ByteBuffer bytes ) throws InvalidDataException {
  		CharsetDecoder decode = Charset.forName( "UTF8" ).newDecoder();
  		decode.onMalformedInput( codingErrorAction );
  		decode.onUnmappableCharacter( codingErrorAction );
  		String s;
  		try {
  			bytes.mark();
  			s = decode.decode( bytes ).toString();
  			bytes.reset();
  		} catch ( CharacterCodingException e ) {
  			throw new InvalidDataException( CloseFrame.NO_UTF8, e );
  		}
  		return s;
  	}
  
  	/**
  	 * Implementation of the "Flexible and Economical UTF-8 Decoder" algorithm
  	 * by Björn Höhrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/)
  	 */
  	private static final int[] utf8d = {
  			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
  			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
  			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
  			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
  			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
  			8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
  			0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
  			0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
  			0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
  			1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
  			1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
  			1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // s7..s8
  	};
  
  	/**
  	 * Check if the provided BytebBuffer contains a valid utf8 encoded string.
  	 * <p>
  	 * Using the algorithm "Flexible and Economical UTF-8 Decoder" by Björn Höhrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/)
  	 *
  	 * @param data the ByteBuffer
  	 * @param off  offset (for performance reasons)
  	 * @return does the ByteBuffer contain a valid utf8 encoded string
  	 */
  	public static boolean isValidUTF8( ByteBuffer data, int off ) {
  		int len = data.remaining();
  		if( len < off ) {
  			return false;
  		}
  		int state = 0;
  		for( int i = off; i < len; ++i ) {
  			state = utf8d[256 + ( state << 4 ) + utf8d[( 0xff & data.get( i ) )]];
  			if( state == 1 ) {
  				return false;
  			}
  		}
  		return true;
  	}
  
  	/**
  	 * Calling isValidUTF8 with offset 0
  	 *
  	 * @param data the ByteBuffer
  	 * @return does the ByteBuffer contain a valid utf8 encoded string
  	 */
  	public static boolean isValidUTF8( ByteBuffer data ) {
  		return isValidUTF8( data, 0 );
  	}
  
  }
  