// ======================================================================== // Copyright (c) 2004-2009 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.io; import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.util.StringUtil; /* ------------------------------------------------------------------------------- */ /** Buffer utility methods. * * */ public class BufferUtil { static final byte SPACE= 0x20; static final byte MINUS= '-'; static final byte[] DIGIT= {(byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7',(byte)'8',(byte)'9',(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F'}; /** * Convert buffer to an integer. * Parses up to the first non-numeric character. If no number is found an * IllegalArgumentException is thrown * @param buffer A buffer containing an integer. The position is not changed. * @return an int */ public static int toInt(Buffer buffer) { int val= 0; boolean started= false; boolean minus= false; for (int i= buffer.getIndex(); i < buffer.putIndex(); i++) { byte b= buffer.peek(i); if (b <= SPACE) { if (started) break; } else if (b >= '0' && b <= '9') { val= val * 10 + (b - '0'); started= true; } else if (b == MINUS && !started) { minus= true; } else break; } if (started) return minus ? (-val) : val; throw new NumberFormatException(buffer.toString()); } /** * Convert buffer to an long. * Parses up to the first non-numeric character. If no number is found an * IllegalArgumentException is thrown * @param buffer A buffer containing an integer. The position is not changed. * @return an int */ public static long toLong(Buffer buffer) { long val= 0; boolean started= false; boolean minus= false; for (int i= buffer.getIndex(); i < buffer.putIndex(); i++) { byte b= buffer.peek(i); if (b <= SPACE) { if (started) break; } else if (b >= '0' && b <= '9') { val= val * 10L + (b - '0'); started= true; } else if (b == MINUS && !started) { minus= true; } else break; } if (started) return minus ? (-val) : val; throw new NumberFormatException(buffer.toString()); } public static void putHexInt(Buffer buffer, int n) { if (n < 0) { buffer.put((byte)'-'); if (n == Integer.MIN_VALUE) { buffer.put((byte)(0x7f&'8')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); buffer.put((byte)(0x7f&'0')); return; } n= -n; } if (n < 0x10) { buffer.put(DIGIT[n]); } else { boolean started= false; // This assumes constant time int arithmatic for (int i= 0; i < hexDivisors.length; i++) { if (n < hexDivisors[i]) { if (started) buffer.put((byte)'0'); continue; } started= true; int d= n / hexDivisors[i]; buffer.put(DIGIT[d]); n= n - d * hexDivisors[i]; } } } /* ------------------------------------------------------------ */ /** * Add hex integer BEFORE current getIndex. * @param buffer * @param n */ public static void prependHexInt(Buffer buffer, int n) { if (n==0) { int gi=buffer.getIndex(); buffer.poke(--gi,(byte)'0'); buffer.setGetIndex(gi); } else { boolean minus=false; if (n<0) { minus=true; n=-n; } int gi=buffer.getIndex(); while(n>0) { int d = 0xf&n; n=n>>4; buffer.poke(--gi,DIGIT[d]); } if (minus) buffer.poke(--gi,(byte)'-'); buffer.setGetIndex(gi); } } /* ------------------------------------------------------------ */ public static void putDecInt(Buffer buffer, int n) { if (n < 0) { buffer.put((byte)'-'); if (n == Integer.MIN_VALUE) { buffer.put((byte)'2'); n= 147483648; } else n= -n; } if (n < 10) { buffer.put(DIGIT[n]); } else { boolean started= false; // This assumes constant time int arithmatic for (int i= 0; i < decDivisors.length; i++) { if (n < decDivisors[i]) { if (started) buffer.put((byte)'0'); continue; } started= true; int d= n / decDivisors[i]; buffer.put(DIGIT[d]); n= n - d * decDivisors[i]; } } } public static void putDecLong(Buffer buffer, long n) { if (n < 0) { buffer.put((byte)'-'); if (n == Long.MIN_VALUE) { buffer.put((byte)'9'); n= 223372036854775808L; } else n= -n; } if (n < 10) { buffer.put(DIGIT[(int)n]); } else { boolean started= false; // This assumes constant time int arithmatic for (int i= 0; i < decDivisorsL.length; i++) { if (n < decDivisorsL[i]) { if (started) buffer.put((byte)'0'); continue; } started= true; long d= n / decDivisorsL[i]; buffer.put(DIGIT[(int)d]); n= n - d * decDivisorsL[i]; } } } public static Buffer toBuffer(long value) { ByteArrayBuffer buf=new ByteArrayBuffer(32); putDecLong(buf, value); return buf; } private final static int[] decDivisors= { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 }; private final static int[] hexDivisors= { 0x10000000, 0x1000000, 0x100000, 0x10000, 0x1000, 0x100, 0x10, 0x1 }; private final static long[] decDivisorsL= { 1000000000000000000L, 100000000000000000L, 10000000000000000L, 1000000000000000L, 100000000000000L, 10000000000000L, 1000000000000L, 100000000000L, 10000000000L, 1000000000L, 100000000L, 10000000L, 1000000L, 100000L, 10000L, 1000L, 100L, 10L, 1L }; public static void putCRLF(Buffer buffer) { buffer.put((byte)13); buffer.put((byte)10); } public static boolean isPrefix(Buffer prefix,Buffer buffer) { if (prefix.length()>buffer.length()) return false; int bi=buffer.getIndex(); for (int i=prefix.getIndex(); i<prefix.putIndex();i++) if (prefix.peek(i)!=buffer.peek(bi++)) return false; return true; } public static String to8859_1_String(Buffer buffer) { if (buffer instanceof CachedBuffer) return buffer.toString(); return buffer.toString(StringUtil.__ISO_8859_1); } }