View Javadoc

    1   /*
    2    * Copyright 2012 The Netty Project
    3    *
    4    * The Netty Project licenses this file to you under the Apache License,
    5    * version 2.0 (the "License"); you may not use this file except in compliance
    6    * with the License. You may obtain a copy of the License at:
    7    *
    8    *   http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13   * License for the specific language governing permissions and limitations
    14   * under the License.
    15   */
    16  /*
    17   * Adaptation of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
    18   *
    19   * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
    20   *
    21   * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    22   * and associated documentation files (the "Software"), to deal in the Software without restriction,
    23   * including without limitation the rights to use, copy, modify, merge, publish, distribute,
    24   * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
    25   * furnished to do so, subject to the following conditions:
    26   *
    27   * The above copyright notice and this permission notice shall be included in all copies or
    28   * substantial portions of the Software.
    29   *
    30   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    31   * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    32   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    33   * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    35   */
    36  package org.jboss.netty.handler.codec.http.websocketx;
    37
    38  /**
    39   * Checks UTF8 bytes for validity before converting it into a string
    40   */
    41  final class UTF8Output {
    42      private static final int UTF8_ACCEPT = 0;
    43      private static final int UTF8_REJECT = 12;
    44
    45      private static final byte[] TYPES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    46              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,
    47              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,
    48              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,
    49              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
    50              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, 7, 7, 7, 7,
    51              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, 8,
    52              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,
    53              2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8,
    54              8, 8, 8, 8, 8, 8 };
    55
    56      private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12,
    57              12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12,
    58              12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,
    59              12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36,
    60              12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12,
    61              12, 12, 12, 12, 12, 12 };
    62
    63      private int state = UTF8_ACCEPT;
    64      private int codep;
    65
    66      private final StringBuilder stringBuilder;
    67
    68      UTF8Output(byte[] bytes) {
    69          stringBuilder = new StringBuilder(bytes.length);
    70          write(bytes);
    71      }
    72
    73      public void write(byte[] bytes) {
    74          for (byte b : bytes) {
    75              write(b);
    76          }
    77      }
    78
    79      public void write(int b) {
    80          byte type = TYPES[b & 0xFF];
    81
    82          codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
    83
    84          state = STATES[state + type];
    85
    86          if (state == UTF8_ACCEPT) {
    87              stringBuilder.append((char) codep);
    88          } else if (state == UTF8_REJECT) {
    89              throw new UTF8Exception("bytes are not UTF-8");
    90          }
    91      }
    92
    93      @Override
    94      public String toString() {
    95          if (state != UTF8_ACCEPT) {
    96              throw new UTF8Exception("bytes are not UTF-8");
    97          }
    98          return stringBuilder.toString();
    99      }
    100 }