001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.util;
030:
031: /**
032: * CharSegment is a section of a character buffer
033: */
034: public class CharSegment implements CharSequence {
035: protected char[] _buffer;
036: protected int _offset;
037: protected int _length;
038:
039: public CharSegment() {
040: }
041:
042: /**
043: * Constructs a char segment based on a char array.
044: */
045: public CharSegment(char[] buffer, int offset, int length) {
046: _buffer = buffer;
047: _offset = offset;
048: _length = length;
049: }
050:
051: /**
052: * Sets the char segment to a new buffer triple.
053: */
054: public void init(char[] buffer, int offset, int length) {
055: _buffer = buffer;
056: _offset = offset;
057: _length = length;
058: }
059:
060: /**
061: * Returns the character count of the buffer's contents.
062: */
063: public int length() {
064: return _length;
065: }
066:
067: /**
068: * Returns the buffer length
069: */
070: public int getLength() {
071: return _length;
072: }
073:
074: public int getOffset() {
075: return _offset;
076: }
077:
078: /**
079: * Returns the char at the specified offset.
080: */
081: public char charAt(int i) {
082: if (i < 0 || _length <= i)
083: throw new IndexOutOfBoundsException();
084:
085: return _buffer[i + _offset];
086: }
087:
088: /**
089: * Returns the last character of the buffer
090: *
091: * @throws IndexOutOfBoundsException for an empty buffer
092: */
093: public char getLastChar() {
094: if (_length == 0)
095: throw new IndexOutOfBoundsException();
096:
097: return _buffer[_offset + _length - 1];
098: }
099:
100: /**
101: * Returns the buffer's char array.
102: */
103: public char[] getBuffer() {
104: return _buffer;
105: }
106:
107: /**
108: * Copies characters to the destination buffer.
109: */
110: public void getChars(int srcBegin, int srcEnd, char[] dst,
111: int dstBegin) {
112: srcBegin += _offset;
113: srcEnd += _offset;
114:
115: char[] buffer = _buffer;
116: while (srcBegin < srcEnd)
117: dst[dstBegin++] = buffer[srcBegin++];
118: }
119:
120: /**
121: * Returns a substring
122: */
123: public String substring(int start) {
124: if (_length < start || start < 0)
125: throw new StringIndexOutOfBoundsException();
126:
127: return new String(_buffer, _offset + start, _length - start);
128: }
129:
130: /**
131: * Returns a substring
132: */
133: public String substring(int start, int end) {
134: if (_length < start || start < 0 || end < start)
135: throw new StringIndexOutOfBoundsException();
136:
137: return new String(_buffer, _offset + start, end - start);
138: }
139:
140: /**
141: * Returns a subsequence
142: */
143: public CharSequence subSequence(int start, int end) {
144: if (_length < start || start < 0 || end < start)
145: throw new StringIndexOutOfBoundsException();
146:
147: return new String(_buffer, _offset + start, end - start);
148: }
149:
150: /**
151: * Returns the index of a character in the CharSegment.
152: */
153: public int indexOf(char ch) {
154: return indexOf(ch, 0);
155: }
156:
157: /**
158: * Returns the index of a character in the CharSegment starting
159: * from an offset.
160: */
161: public final int indexOf(char ch, int start) {
162: if (start < 0)
163: start = 0;
164:
165: int end = _offset + _length;
166: start += _offset;
167:
168: char[] buffer = _buffer;
169: for (; start < end; start++) {
170: if (buffer[start] == ch)
171: return start - _offset;
172: }
173:
174: return -1;
175: }
176:
177: /**
178: * Returns the last index of a character in the CharSegment.
179: */
180: public final int lastIndexOf(char ch) {
181: return lastIndexOf(ch, _length - 1);
182: }
183:
184: /**
185: * Returns the last index of a character in the CharSegment starting
186: * from an offset.
187: */
188:
189: public final int lastIndexOf(char ch, int start) {
190: if (_length <= start)
191: start = _length - 1;
192:
193: char[] buffer = _buffer;
194: int offset = _offset;
195: for (; start >= 0; start--) {
196: if (buffer[start + offset] == ch)
197: return start;
198: }
199:
200: return -1;
201: }
202:
203: public int indexOf(String s) {
204: return indexOf(s, 0);
205: }
206:
207: public int indexOf(String s, int start) {
208: int slen = s.length();
209:
210: if (start < 0)
211: start = 0;
212:
213: int end = _offset + _length - slen + 1;
214: start += _offset;
215:
216: char[] buffer = _buffer;
217: for (; start < end; start++) {
218: int i = 0;
219: for (; i < slen; i++) {
220: if (buffer[start + i] != s.charAt(i))
221: break;
222: }
223: if (i == slen)
224: return start - _offset;
225: }
226:
227: return -1;
228: }
229:
230: /**
231: * Returns the buffer's hash code
232: */
233: public int hashCode() {
234: int hash = 0;
235: char[] buffer = _buffer;
236: int begin = _offset;
237: int end = begin + _length;
238:
239: for (; begin < end; begin++)
240: hash = 65521 * hash + buffer[begin] * 251 + 1021;
241:
242: return hash;
243: }
244:
245: /*
246: * Predicate testing if two char segments are equal
247: */
248: public final boolean equals(Object a) {
249: if (this == a)
250: return true;
251:
252: else if (a instanceof CharSegment) {
253: CharSegment cb = (CharSegment) a;
254:
255: int length = _length;
256: if (length != cb._length)
257: return false;
258:
259: char[] buffer = _buffer;
260: char[] aBuffer = cb._buffer;
261:
262: int offset = _offset;
263: int aOffset = cb._offset;
264:
265: for (int i = length - 1; i >= 0; i--)
266: if (buffer[offset + i] != aBuffer[aOffset + i])
267: return false;
268:
269: return true;
270: } else if (a instanceof CharSequence) {
271: CharSequence seq = (CharSequence) a;
272:
273: int length = seq.length();
274:
275: if (_length != length)
276: return false;
277:
278: for (int i = length - 1; i >= 0; i--) {
279: if (_buffer[i] != seq.charAt(i))
280: return false;
281: }
282:
283: return true;
284: } else
285: return false;
286: }
287:
288: /**
289: * Returns true if the two char segments are equal.
290: */
291: public boolean equals(CharSegment cb) {
292: int length = _length;
293: if (length != cb._length)
294: return false;
295:
296: char[] buffer = _buffer;
297: char[] aBuffer = cb._buffer;
298:
299: int offset = _offset;
300: int aOffset = cb._offset;
301:
302: for (int i = length - 1; i >= 0; i--)
303: if (buffer[offset + i] != aBuffer[aOffset + i])
304: return false;
305:
306: return true;
307: }
308:
309: /**
310: * Returns true if the CharSegment equals the char array.
311: */
312: public final boolean equals(char[] cb, int length) {
313: if (length != _length)
314: return false;
315:
316: int offset = _offset;
317: char[] buffer = _buffer;
318:
319: for (int i = _length - 1; i >= 0; i--)
320: if (buffer[offset + i] != cb[i])
321: return false;
322:
323: return true;
324: }
325:
326: /**
327: * Returns true if the CharSegment equals the string.
328: */
329: public final boolean equalsIgnoreCase(String a) {
330: int len = a.length();
331: if (_length != len)
332: return false;
333:
334: int offset = _offset;
335: char[] buffer = _buffer;
336:
337: for (int i = 0; i < len; i++) {
338: char ca = buffer[offset + i];
339: char cb = a.charAt(i);
340:
341: if (ca == cb) {
342: }
343:
344: else if (Character.toLowerCase(ca) != Character
345: .toLowerCase(cb))
346: return false;
347: }
348:
349: return true;
350: }
351:
352: /**
353: * Returns true if the two CharSegments are equivalent ignoring the case.
354: */
355: public final boolean equalsIgnoreCase(CharSegment b) {
356: int length = _length;
357: if (length != b._length)
358: return false;
359:
360: char[] buffer = _buffer;
361: char[] bBuffer = b._buffer;
362:
363: int offset = _offset;
364: int bOffset = b._offset;
365:
366: for (int i = length - 1; i >= 0; i--) {
367: char ca = buffer[offset + i];
368: char cb = bBuffer[bOffset + i];
369:
370: if (ca != cb
371: && Character.toLowerCase(ca) != Character
372: .toLowerCase(cb))
373: return false;
374: }
375: return true;
376: }
377:
378: /*
379: * XXX: unsure is this is legit
380: */
381: public final boolean matches(Object a) {
382: if (a instanceof CharSegment) {
383: CharSegment cb = (CharSegment) a;
384: if (_length != cb._length)
385: return false;
386:
387: int offset = _offset;
388: int bOffset = cb._offset;
389:
390: char[] buffer = _buffer;
391: char[] cbBuffer = cb._buffer;
392:
393: for (int i = _length - 1; i >= 0; i--)
394: if (buffer[offset + i] != cbBuffer[bOffset + i])
395: return false;
396:
397: return true;
398: } else if (a instanceof String) {
399: String sa = (String) a;
400:
401: if (_length != sa.length())
402: return false;
403:
404: int offset = _offset;
405: char[] buffer = _buffer;
406:
407: for (int i = _length - 1; i >= 0; i--)
408: if (buffer[i + offset] != sa.charAt(i))
409: return false;
410:
411: return true;
412: } else
413: return false;
414: }
415:
416: /**
417: * Returns true if the charSegment matches the string.
418: */
419: public boolean matches(String sa) {
420: if (_length != sa.length())
421: return false;
422:
423: char[] buffer = _buffer;
424: int offset = _offset;
425:
426: for (int i = _length - 1; i >= 0; i--)
427: if (_buffer[_offset + i] != sa.charAt(i))
428: return false;
429:
430: return true;
431: }
432:
433: /**
434: * Returns true if the CharSegment matches the string, ignoring the case.
435: */
436: public boolean matchesIgnoreCase(String sa) {
437: if (_length != sa.length())
438: return false;
439:
440: char[] buffer = _buffer;
441: int offset = _offset;
442: for (int i = _length - 1; i >= 0; i--) {
443: char ca = buffer[offset + i];
444: char cb = sa.charAt(i);
445:
446: if (ca != cb
447: && Character.toLowerCase(ca) != Character
448: .toLowerCase(cb))
449: return false;
450: }
451:
452: return true;
453: }
454:
455: public boolean regionMatches(int off1, CharSegment buf, int off2,
456: int len) {
457: if (_length < off1 + len || buf._length < off2 + len)
458: return false;
459:
460: char[] buffer = _buffer;
461: char[] bufBuffer = buf._buffer;
462: for (int i = len - 1; i >= 0; i--) {
463: if (buffer[off1 + i] != bufBuffer[off2 + i])
464: return false;
465: }
466:
467: return true;
468: }
469:
470: public boolean regionMatches(int off1, String buf, int off2, int len) {
471: if (_length < off1 + len || buf.length() < off2 + len)
472: return false;
473:
474: char[] buffer = _buffer;
475: for (int i = 0; i < len; i++) {
476: if (buffer[off1 + i] != buf.charAt(off2 + i))
477: return false;
478: }
479:
480: return true;
481: }
482:
483: public boolean regionMatchesIgnoreCase(int off1, CharSegment buf,
484: int off2, int len) {
485: if (_length < off1 + len || buf._length < off2 + len)
486: return false;
487:
488: char[] buffer = _buffer;
489: char[] bufBuffer = buf._buffer;
490: for (int i = len - 1; i >= 0; i--) {
491: if (Character.toLowerCase(buffer[off1 + i]) != Character
492: .toLowerCase(bufBuffer[off2 + i]))
493: return false;
494: }
495:
496: return true;
497: }
498:
499: /**
500: * Returns true if the CharSegment starts with the string.
501: */
502: public boolean startsWith(String string) {
503: if (string == null)
504: return false;
505:
506: int strlen = string.length();
507: if (_length < strlen)
508: return false;
509:
510: char[] buffer = _buffer;
511: int offset = _offset;
512:
513: while (--strlen >= 0) {
514: if (buffer[offset + strlen] != string.charAt(strlen))
515: return false;
516: }
517:
518: return true;
519: }
520:
521: /**
522: * Returns true if the CharSegment ends with the string.
523: */
524: public boolean endsWith(String string) {
525: if (string == null)
526: return false;
527:
528: int strlen = string.length();
529: if (_length < strlen)
530: return false;
531:
532: char[] buffer = _buffer;
533: int offset = _offset + _length - strlen;
534:
535: while (--strlen >= 0) {
536: if (buffer[offset + strlen] != string.charAt(strlen))
537: return false;
538: }
539:
540: return true;
541: }
542:
543: /**
544: * Returns true if the CharSegment ends with the char segment.
545: */
546: public boolean endsWith(CharSegment cb) {
547: if (cb == null)
548: return false;
549:
550: int strlen = cb._length;
551: if (_length < strlen)
552: return false;
553:
554: char[] buffer = _buffer;
555: int offset = _offset + _length - strlen;
556:
557: char[] cbBuffer = cb._buffer;
558: int cbOffset = cb._offset;
559:
560: while (--strlen >= 0) {
561: if (buffer[offset + strlen] != cbBuffer[cbOffset + strlen])
562: return false;
563: }
564:
565: return true;
566: }
567:
568: /**
569: * Converts the contents of the segment to lower case.
570: */
571: public CharSegment toLowerCase() {
572: char[] buffer = _buffer;
573: int len = _length;
574: int offset = _offset;
575:
576: while (--len >= 0)
577: buffer[offset + len] = Character.toLowerCase(buffer[offset
578: + len]);
579:
580: return this ;
581: }
582:
583: /**
584: * String representation of the buffer.
585: */
586: public String toString() {
587: return new String(_buffer, _offset, _length);
588: }
589: }
|