package org.glassfish.grizzly.http.util;
import java.nio.charset.Charset;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.memory.Buffers;
public class BufferChunk implements Chunk {
private static final Charset DEFAULT_CHARSET = Constants.DEFAULT_HTTP_CHARSET;
private Buffer buffer;
private int start;
private int end;
private int limit;
String cachedString;
Charset cachedStringCharset;
public void setBufferChunk(final Buffer buffer, final int start, final int end) {
setBufferChunk(buffer, start, end, end);
}
public void setBufferChunk(final Buffer buffer, final int start, final int end, final int limit) {
this.buffer = buffer;
this.start = start;
this.end = end;
this.limit = limit;
resetStringCache();
}
public Buffer getBuffer() {
return buffer;
}
public void setBuffer(Buffer buffer) {
this.buffer = buffer;
resetStringCache();
}
@Override
public int getStart() {
return start;
}
@Override
public void setStart(int start) {
this.start = start;
resetStringCache();
}
@Override
public int getEnd() {
return end;
}
@Override
public void setEnd(int end) {
this.end = end;
resetStringCache();
}
@Override
public final int getLength() {
return end - start;
}
public final boolean isNull() {
return buffer == null;
}
public void allocate(final int size) {
if (isNull() || limit - start < size) {
setBufferChunk(Buffers.wrap(null, new byte[size]), 0, 0, size);
}
end = start;
}
@Override
public void delete(final int start, final int end) {
final int absDeleteStart = this.start + start;
final int absDeleteEnd = this.start + end;
final int diff = this.end - absDeleteEnd;
if (diff == 0) {
this.end = absDeleteStart;
} else {
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
try {
Buffers.setPositionLimit(buffer, absDeleteStart, absDeleteStart + diff);
final Buffer duplicate = buffer.duplicate();
buffer.put(duplicate, absDeleteEnd, diff);
this.end = absDeleteStart + diff;
} finally {
Buffers.setPositionLimit(buffer, oldPos, oldLim);
}
}
resetStringCache();
}
public void append(final BufferChunk bc) {
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
final int srcLen = bc.getLength();
Buffers.setPositionLimit(buffer, end, end + srcLen);
buffer.put(bc.getBuffer(), bc.getStart(), srcLen);
Buffers.setPositionLimit(buffer, oldPos, oldLim);
end += srcLen;
}
@Override
public final int indexOf(final char c, final int fromIndex) {
final int idx = indexOf(buffer, start + fromIndex, end, c);
return idx >= start ? idx - start : -1;
}
@Override
public final int indexOf(final String s, final int fromIndex) {
final int idx = indexOf(buffer, start + fromIndex, end, s);
return idx >= start ? idx - start : -1;
}
boolean startsWith(String s, int pos) {
final int len = s.length();
if (len > getLength() - pos) {
return false;
}
int off = start + pos;
for (int i = 0; i < len; i++) {
if (buffer.get(off++) != s.charAt(i)) {
return false;
}
}
return true;
}
public boolean startsWithIgnoreCase(String s, int pos) {
final int len = s.length();
if (len > getLength() - pos) {
return false;
}
int off = start + pos;
for (int i = 0; i < len; i++) {
if (Ascii.toLower(buffer.get(off++)) != Ascii.toLower(s.charAt(i))) {
return false;
}
}
return true;
}
public int findBytesAscii(byte[] b) {
final byte first = b[0];
final int from = getStart();
final int to = getEnd();
int srcEnd = b.length;
for (int i = from; i <= to - srcEnd; i++) {
if (Ascii.toLower(buffer.get(i)) != first) {
continue;
}
int myPos = i + 1;
for (int srcPos = 1; srcPos < srcEnd;) {
if (Ascii.toLower(buffer.get(myPos++)) != b[srcPos++]) {
break;
}
if (srcPos == srcEnd) {
return i - from;
}
}
}
return -1;
}
@Override
public int hashCode() {
return hash();
}
public int hash() {
int code = 0;
for (int i = start; i < end; i++) {
code = code * 31 + buffer.get(i);
}
return code;
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof BufferChunk)) {
return false;
}
final BufferChunk anotherBC = (BufferChunk) o;
final int len = getLength();
if (len != anotherBC.getLength()) {
return false;
}
int offs1 = start;
int offs2 = anotherBC.start;
for (int i = 0; i < len; i++) {
if (buffer.get(offs1++) != anotherBC.buffer.get(offs2++)) {
return false;
}
}
return true;
}
public boolean equals(CharSequence s) {
if (getLength() != s.length()) {
return false;
}
for (int i = start; i < end; i++) {
if (buffer.get(i) != s.charAt(i - start)) {
return false;
}
}
return true;
}
public boolean equals(final byte[] b) {
return equals(b, 0, b.length);
}
public boolean equals(final byte[] b, int offset, final int len) {
if (getLength() != len) {
return false;
}
for (int i = start; i < end; i++) {
if (buffer.get(i) != b[offset++]) {
return false;
}
}
return true;
}
public static boolean equals(final byte[] c, final int cOff, final int cLen, final Buffer t, final int tOff, final int tLen) {
if (cLen != tLen) {
return false;
}
if (c == null || t == null) {
return false;
}
for (int i = 0; i < cLen; i++) {
if (c[i + cOff] != t.get(i + tOff)) {
return false;
}
}
return true;
}
public boolean equals(final char[] b, int offset, final int len) {
if (getLength() != len) {
return false;
}
for (int i = start; i < end; i++) {
if (buffer.get(i) != b[offset++]) {
return false;
}
}
return true;
}
public boolean equalsIgnoreCase(final Object o) {
if (!(o instanceof BufferChunk)) {
return false;
}
final BufferChunk anotherBC = (BufferChunk) o;
final int len = getLength();
if (len != anotherBC.getLength()) {
return false;
}
int offs1 = start;
int offs2 = anotherBC.start;
for (int i = 0; i < len; i++) {
if (Ascii.toLower(buffer.get(offs1++)) != Ascii.toLower(anotherBC.buffer.get(offs2++))) {
return false;
}
}
return true;
}
public boolean equalsIgnoreCase(CharSequence s) {
if (getLength() != s.length()) {
return false;
}
for (int i = start; i < end; i++) {
if (Ascii.toLower(buffer.get(i)) != Ascii.toLower(s.charAt(i - start))) {
return false;
}
}
return true;
}
public boolean equalsIgnoreCase(final byte[] b) {
return equalsIgnoreCase(b, 0, b.length);
}
public boolean equalsIgnoreCase(final byte[] b, final int offset, final int len) {
if (getLength() != len) {
return false;
}
int offs1 = start;
int offs2 = offset;
for (int i = 0; i < len; i++) {
if (Ascii.toLower(buffer.get(offs1++)) != Ascii.toLower(b[offs2++])) {
return false;
}
}
return true;
}
public boolean equalsIgnoreCase(final char[] b, int offset, final int len) {
if (getLength() != len) {
return false;
}
for (int i = start; i < end; i++) {
if (Ascii.toLower(buffer.get(i)) != Ascii.toLower(b[offset++])) {
return false;
}
}
return true;
}
public boolean equalsIgnoreCaseLowerCase(final byte[] b) {
return equalsIgnoreCaseLowerCase(buffer, start, end, b);
}
@Override
public String toString() {
return toString(null);
}
public String toString(Charset charset) {
if (charset == null) {
charset = DEFAULT_CHARSET;
}
if (cachedString != null && charset.equals(cachedStringCharset)) {
return cachedString;
}
cachedString = buffer.toStringContent(charset, start, end);
cachedStringCharset = charset;
return cachedString;
}
@Override
public String toString(final int start, final int end) {
return buffer.toStringContent(DEFAULT_CHARSET, this.start + start, this.start + end);
}
protected final void resetStringCache() {
cachedString = null;
cachedStringCharset = null;
}
protected final void reset() {
buffer = null;
start = -1;
end = -1;
limit = -1;
resetStringCache();
}
public final void recycle() {
reset();
}
protected void notifyDirectUpdate() {
}
public static int indexOf(final Buffer buffer, int off, final int end, final char qq) {
while (off < end) {
final byte b = buffer.get(off);
if (b == qq) {
return off;
}
off++;
}
return -1;
}
public static int indexOf(final Buffer buffer, int off, final int end, final CharSequence s) {
final int strLen = s.length();
if (strLen == 0) {
return off;
}
if (strLen > end - off) {
return -1;
}
int strOffs = 0;
final int lastOffs = end - strLen;
while (off <= lastOffs + strOffs) {
final byte b = buffer.get(off);
if (b == s.charAt(strOffs)) {
strOffs++;
if (strOffs == strLen) {
return off - strLen + 1;
}
} else {
strOffs = 0;
}
off++;
}
return -1;
}
public int compareIgnoreCase(int start, int end, String compareTo) {
int result = 0;
int len = compareTo.length();
if (end - start < len) {
len = end - start;
}
for (int i = 0; i < len && result == 0; i++) {
if (Ascii.toLower(buffer.get(i + start)) > Ascii.toLower(compareTo.charAt(i))) {
result = 1;
} else if (Ascii.toLower(buffer.get(i + start)) < Ascii.toLower(compareTo.charAt(i))) {
result = -1;
}
}
if (result == 0) {
if (compareTo.length() > end - start) {
result = -1;
} else if (compareTo.length() < end - start) {
result = 1;
}
}
return result;
}
public int compare(int start, int end, String compareTo) {
int result = 0;
int len = compareTo.length();
if (end - start < len) {
len = end - start;
}
for (int i = 0; i < len && result == 0; i++) {
if (buffer.get(i + start) > compareTo.charAt(i)) {
result = 1;
} else if (buffer.get(i + start) < compareTo.charAt(i)) {
result = -1;
}
}
if (result == 0) {
if (compareTo.length() > end - start) {
result = -1;
} else if (compareTo.length() < end - start) {
result = 1;
}
}
return result;
}
public static boolean equalsIgnoreCaseLowerCase(final Buffer buffer, final int start, final int end, final byte[] cmpTo) {
final int len = end - start;
if (len != cmpTo.length) {
return false;
}
for (int i = 0; i < len; i++) {
if (Ascii.toLower(buffer.get(i + start)) != cmpTo[i]) {
return false;
}
}
return true;
}
public static boolean startsWith(final Buffer buffer, final int start, final int end, final byte[] cmpTo) {
final int len = end - start;
if (len < cmpTo.length) {
return false;
}
for (int i = 0; i < cmpTo.length; i++) {
if (buffer.get(start + i) != cmpTo[i]) {
return false;
}
}
return true;
}
public void trimLeft() {
boolean modified = false;
while (buffer.get(start) <= 0x20) {
modified = true;
start++;
}
if (modified) {
resetStringCache();
}
}
}