1 // ======================================================================== 2 // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // ======================================================================== 14 15 package org.mortbay.io; 16 17 import java.io.IOException; 18 import java.io.InputStream; 19 import java.io.OutputStream; 20 import java.io.UnsupportedEncodingException; 21 import java.util.Arrays; 22 23 /* ------------------------------------------------------------------------------- */ 24 /** 25 * @author gregw 26 */ 27 public class ByteArrayBuffer extends AbstractBuffer 28 { 29 protected byte[] _bytes; 30 ByteArrayBuffer(int access, boolean isVolatile)31 protected ByteArrayBuffer(int access, boolean isVolatile) 32 { 33 super(access, isVolatile); 34 } 35 ByteArrayBuffer(byte[] bytes)36 public ByteArrayBuffer(byte[] bytes) 37 { 38 this(bytes, 0, bytes.length, READWRITE); 39 } 40 ByteArrayBuffer(byte[] bytes, int index, int length)41 public ByteArrayBuffer(byte[] bytes, int index, int length) 42 { 43 this(bytes, index, length, READWRITE); 44 } 45 ByteArrayBuffer(byte[] bytes, int index, int length, int access)46 public ByteArrayBuffer(byte[] bytes, int index, int length, int access) 47 { 48 super(READWRITE, NON_VOLATILE); 49 _bytes = bytes; 50 setPutIndex(index + length); 51 setGetIndex(index); 52 _access = access; 53 } 54 ByteArrayBuffer(byte[] bytes, int index, int length, int access, boolean isVolatile)55 public ByteArrayBuffer(byte[] bytes, int index, int length, int access, boolean isVolatile) 56 { 57 super(READWRITE, isVolatile); 58 _bytes = bytes; 59 setPutIndex(index + length); 60 setGetIndex(index); 61 _access = access; 62 } 63 ByteArrayBuffer(int size)64 public ByteArrayBuffer(int size) 65 { 66 this(new byte[size], 0, size, READWRITE); 67 setPutIndex(0); 68 } 69 ByteArrayBuffer(String value)70 public ByteArrayBuffer(String value) 71 { 72 super(READWRITE,NON_VOLATILE); 73 _bytes = Portable.getBytes(value); 74 setGetIndex(0); 75 setPutIndex(_bytes.length); 76 _access=IMMUTABLE; 77 _string = value; 78 } 79 ByteArrayBuffer(String value,String encoding)80 public ByteArrayBuffer(String value,String encoding) throws UnsupportedEncodingException 81 { 82 super(READWRITE,NON_VOLATILE); 83 _bytes = value.getBytes(encoding); 84 setGetIndex(0); 85 setPutIndex(_bytes.length); 86 _access=IMMUTABLE; 87 _string = value; 88 } 89 array()90 public byte[] array() 91 { 92 return _bytes; 93 } 94 capacity()95 public int capacity() 96 { 97 return _bytes.length; 98 } 99 compact()100 public void compact() 101 { 102 if (isReadOnly()) 103 throw new IllegalStateException(__READONLY); 104 int s = markIndex() >= 0 ? markIndex() : getIndex(); 105 if (s > 0) 106 { 107 int length = putIndex() - s; 108 if (length > 0) 109 { 110 Portable.arraycopy(_bytes, s,_bytes, 0, length); 111 } 112 if (markIndex() > 0) setMarkIndex(markIndex() - s); 113 setGetIndex(getIndex() - s); 114 setPutIndex(putIndex() - s); 115 } 116 } 117 118 equals(Object obj)119 public boolean equals(Object obj) 120 { 121 if (obj==this) 122 return true; 123 124 if (obj == null || !(obj instanceof Buffer)) 125 return false; 126 127 if (obj instanceof Buffer.CaseInsensitve) 128 return equalsIgnoreCase((Buffer)obj); 129 130 131 Buffer b = (Buffer) obj; 132 133 // reject different lengths 134 if (b.length() != length()) 135 return false; 136 137 // reject AbstractBuffer with different hash value 138 if (_hash != 0 && obj instanceof AbstractBuffer) 139 { 140 AbstractBuffer ab = (AbstractBuffer) obj; 141 if (ab._hash != 0 && _hash != ab._hash) 142 return false; 143 } 144 145 // Nothing for it but to do the hard grind. 146 int get=getIndex(); 147 int bi=b.putIndex(); 148 for (int i = putIndex(); i-->get;) 149 { 150 byte b1 = _bytes[i]; 151 byte b2 = b.peek(--bi); 152 if (b1 != b2) return false; 153 } 154 return true; 155 } 156 157 equalsIgnoreCase(Buffer b)158 public boolean equalsIgnoreCase(Buffer b) 159 { 160 if (b==this) 161 return true; 162 163 // reject different lengths 164 if (b==null || b.length() != length()) 165 return false; 166 167 // reject AbstractBuffer with different hash value 168 if (_hash != 0 && b instanceof AbstractBuffer) 169 { 170 AbstractBuffer ab = (AbstractBuffer) b; 171 if (ab._hash != 0 && _hash != ab._hash) return false; 172 } 173 174 // Nothing for it but to do the hard grind. 175 int get=getIndex(); 176 int bi=b.putIndex(); 177 byte[] barray=b.array(); 178 if (barray==null) 179 { 180 for (int i = putIndex(); i-->get;) 181 { 182 byte b1 = _bytes[i]; 183 byte b2 = b.peek(--bi); 184 if (b1 != b2) 185 { 186 if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A'); 187 if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A'); 188 if (b1 != b2) return false; 189 } 190 } 191 } 192 else 193 { 194 for (int i = putIndex(); i-->get;) 195 { 196 byte b1 = _bytes[i]; 197 byte b2 = barray[--bi]; 198 if (b1 != b2) 199 { 200 if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A'); 201 if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A'); 202 if (b1 != b2) return false; 203 } 204 } 205 } 206 return true; 207 } 208 get()209 public byte get() 210 { 211 return _bytes[_get++]; 212 } 213 hashCode()214 public int hashCode() 215 { 216 if (_hash == 0 || _hashGet!=_get || _hashPut!=_put) 217 { 218 int get=getIndex(); 219 for (int i = putIndex(); i-- >get;) 220 { 221 byte b = _bytes[i]; 222 if ('a' <= b && b <= 'z') 223 b = (byte) (b - 'a' + 'A'); 224 _hash = 31 * _hash + b; 225 } 226 if (_hash == 0) 227 _hash = -1; 228 _hashGet=_get; 229 _hashPut=_put; 230 } 231 return _hash; 232 } 233 234 peek(int index)235 public byte peek(int index) 236 { 237 return _bytes[index]; 238 } 239 peek(int index, byte[] b, int offset, int length)240 public int peek(int index, byte[] b, int offset, int length) 241 { 242 int l = length; 243 if (index + l > capacity()) 244 { 245 l = capacity() - index; 246 if (l==0) 247 return -1; 248 } 249 250 if (l < 0) 251 return -1; 252 253 Portable.arraycopy(_bytes, index, b, offset, l); 254 return l; 255 } 256 poke(int index, byte b)257 public void poke(int index, byte b) 258 { 259 /* 260 if (isReadOnly()) 261 throw new IllegalStateException(__READONLY); 262 263 if (index < 0) 264 throw new IllegalArgumentException("index<0: " + index + "<0"); 265 if (index > capacity()) 266 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity()); 267 */ 268 _bytes[index] = b; 269 } 270 poke(int index, Buffer src)271 public int poke(int index, Buffer src) 272 { 273 _hash=0; 274 275 /* 276 if (isReadOnly()) 277 throw new IllegalStateException(__READONLY); 278 if (index < 0) 279 throw new IllegalArgumentException("index<0: " + index + "<0"); 280 */ 281 282 int length=src.length(); 283 if (index + length > capacity()) 284 { 285 length=capacity()-index; 286 /* 287 if (length<0) 288 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity()); 289 */ 290 } 291 292 byte[] src_array = src.array(); 293 if (src_array != null) 294 Portable.arraycopy(src_array, src.getIndex(), _bytes, index, length); 295 else if (src_array != null) 296 { 297 int s=src.getIndex(); 298 for (int i=0;i<length;i++) 299 poke(index++,src_array[s++]); 300 } 301 else 302 { 303 int s=src.getIndex(); 304 for (int i=0;i<length;i++) 305 _bytes[index++]=src.peek(s++); 306 } 307 308 return length; 309 } 310 311 poke(int index, byte[] b, int offset, int length)312 public int poke(int index, byte[] b, int offset, int length) 313 { 314 _hash=0; 315 /* 316 if (isReadOnly()) 317 throw new IllegalStateException(__READONLY); 318 if (index < 0) 319 throw new IllegalArgumentException("index<0: " + index + "<0"); 320 */ 321 322 if (index + length > capacity()) 323 { 324 length=capacity()-index; 325 /* if (length<0) 326 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity()); 327 */ 328 } 329 330 Portable.arraycopy(b, offset, _bytes, index, length); 331 332 return length; 333 } 334 335 /* ------------------------------------------------------------ */ 336 /** Wrap a byte array. 337 * @param b 338 * @param off 339 * @param len 340 */ wrap(byte[] b, int off, int len)341 public void wrap(byte[] b, int off, int len) 342 { 343 if (isReadOnly()) throw new IllegalStateException(__READONLY); 344 if (isImmutable()) throw new IllegalStateException(__IMMUTABLE); 345 _bytes=b; 346 clear(); 347 setGetIndex(off); 348 setPutIndex(off+len); 349 } 350 351 /* ------------------------------------------------------------ */ 352 /** Wrap a byte array 353 * @param b 354 */ wrap(byte[] b)355 public void wrap(byte[] b) 356 { 357 if (isReadOnly()) throw new IllegalStateException(__READONLY); 358 if (isImmutable()) throw new IllegalStateException(__IMMUTABLE); 359 _bytes=b; 360 setGetIndex(0); 361 setPutIndex(b.length); 362 } 363 364 /* ------------------------------------------------------------ */ writeTo(OutputStream out)365 public void writeTo(OutputStream out) 366 throws IOException 367 { 368 out.write(_bytes,getIndex(),length()); 369 clear(); 370 } 371 372 /* ------------------------------------------------------------ */ readFrom(InputStream in,int max)373 public int readFrom(InputStream in,int max) throws IOException 374 { 375 if (max<0||max>space()) 376 max=space(); 377 int p = putIndex(); 378 379 int len=0, total=0, available=max; 380 while (total<max) 381 { 382 len=in.read(_bytes,p,available); 383 if (len<0) 384 break; 385 else if (len>0) 386 { 387 p += len; 388 total += len; 389 available -= len; 390 setPutIndex(p); 391 } 392 if (in.available()<=0) 393 break; 394 } 395 if (len<0 && total==0) 396 return -1; 397 return total; 398 } 399 400 /* ------------------------------------------------------------ */ space()401 public int space() 402 { 403 return _bytes.length - _put; 404 } 405 406 407 /* ------------------------------------------------------------ */ 408 /* ------------------------------------------------------------ */ 409 /* ------------------------------------------------------------ */ 410 public static class CaseInsensitive extends ByteArrayBuffer implements Buffer.CaseInsensitve 411 { CaseInsensitive(String s)412 public CaseInsensitive(String s) 413 { 414 super(s); 415 } 416 CaseInsensitive(byte[] b, int o, int l, int rw)417 public CaseInsensitive(byte[] b, int o, int l, int rw) 418 { 419 super(b,o,l,rw); 420 } 421 equals(Object obj)422 public boolean equals(Object obj) 423 { 424 return equalsIgnoreCase((Buffer)obj); 425 } 426 427 } 428 } 429