1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.util; 20 21 import java.nio.ByteBuffer; 22 23 /** 24 * Stateful parser for lines of UTF8 formatted text, looking for <code>"\n"</code> as a line termination character. 25 * <p> 26 * For use with new IO framework that is based on ByteBuffer parsing. 27 */ 28 public class Utf8LineParser 29 { 30 private enum State 31 { 32 START, 33 PARSE, 34 END; 35 } 36 37 private State state; 38 private Utf8StringBuilder utf; 39 40 public Utf8LineParser() 41 { 42 this.state = State.START; 43 } 44 45 /** 46 * Parse a ByteBuffer (could be a partial buffer), and return once a complete line of UTF8 parsed text has been reached. 47 * 48 * @param buf 49 * the buffer to parse (could be an incomplete buffer) 50 * @return the line of UTF8 parsed text, or null if no line end termination has been reached within the {@link ByteBuffer#remaining() remaining} bytes of 51 * the provided ByteBuffer. (In the case of a null, a subsequent ByteBuffer with a line end termination should be provided) 52 * @throws NotUtf8Exception 53 * if the input buffer has bytes that do not conform to UTF8 validation (validation performed by {@link Utf8StringBuilder} 54 */ 55 public String parse(ByteBuffer buf) 56 { 57 byte b; 58 while (buf.remaining() > 0) 59 { 60 b = buf.get(); 61 if (parseByte(b)) 62 { 63 state = State.START; 64 return utf.toString(); 65 } 66 } 67 // have not reached end of line (yet) 68 return null; 69 } 70 71 private boolean parseByte(byte b) 72 { 73 switch (state) 74 { 75 case START: 76 utf = new Utf8StringBuilder(); 77 state = State.PARSE; 78 return parseByte(b); 79 case PARSE: 80 // not waiting on more UTF sequence parts. 81 if (utf.isUtf8SequenceComplete() && ((b == '\r') || (b == '\n'))) 82 { 83 state = State.END; 84 return parseByte(b); 85 } 86 utf.append(b); 87 break; 88 case END: 89 if (b == '\n') 90 { 91 // we've reached the end 92 state = State.START; 93 return true; 94 } 95 break; 96 } 97 return false; 98 } 99 }