Komplettes G-Earth Paket inkl. JRE, Extensions und Tools. Extensions: - G-BuildTools, G-Click Ultimate, G-Loader, G-Manipulate - G-Presets, G-Translator, G-Trigger, G-itemViewer - Market Utils, Packet Info Explorer, Plants - RandomRoomVisitor, RoomLogger, Sanbovir Photo Inspector - SpyFriends, WallAligner, XabboScripter, xabbo
1326 lines
41 KiB
Java
1326 lines
41 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*/
|
|
package okio;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.nio.charset.Charset;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import okio.BufferedSink;
|
|
import okio.BufferedSource;
|
|
import okio.ByteString;
|
|
import okio.Segment;
|
|
import okio.SegmentPool;
|
|
import okio.SegmentedByteString;
|
|
import okio.Sink;
|
|
import okio.Source;
|
|
import okio.Timeout;
|
|
import okio.Util;
|
|
|
|
public final class Buffer
|
|
implements BufferedSource,
|
|
BufferedSink,
|
|
Cloneable {
|
|
private static final byte[] DIGITS = new byte[]{48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
|
|
static final int REPLACEMENT_CHARACTER = 65533;
|
|
Segment head;
|
|
long size;
|
|
|
|
public long size() {
|
|
return this.size;
|
|
}
|
|
|
|
@Override
|
|
public Buffer buffer() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public OutputStream outputStream() {
|
|
return new OutputStream(){
|
|
|
|
@Override
|
|
public void write(int b) {
|
|
Buffer.this.writeByte((byte)b);
|
|
}
|
|
|
|
@Override
|
|
public void write(byte[] data, int offset, int byteCount) {
|
|
Buffer.this.write(data, offset, byteCount);
|
|
}
|
|
|
|
@Override
|
|
public void flush() {
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
}
|
|
|
|
public String toString() {
|
|
return this + ".outputStream()";
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public Buffer emitCompleteSegments() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public BufferedSink emit() {
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public boolean exhausted() {
|
|
return this.size == 0L;
|
|
}
|
|
|
|
@Override
|
|
public void require(long byteCount) throws EOFException {
|
|
if (this.size < byteCount) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean request(long byteCount) {
|
|
return this.size >= byteCount;
|
|
}
|
|
|
|
@Override
|
|
public InputStream inputStream() {
|
|
return new InputStream(){
|
|
|
|
@Override
|
|
public int read() {
|
|
if (Buffer.this.size > 0L) {
|
|
return Buffer.this.readByte() & 0xFF;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public int read(byte[] sink, int offset, int byteCount) {
|
|
return Buffer.this.read(sink, offset, byteCount);
|
|
}
|
|
|
|
@Override
|
|
public int available() {
|
|
return (int)Math.min(Buffer.this.size, Integer.MAX_VALUE);
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
}
|
|
|
|
public String toString() {
|
|
return Buffer.this + ".inputStream()";
|
|
}
|
|
};
|
|
}
|
|
|
|
public Buffer copyTo(OutputStream out) throws IOException {
|
|
return this.copyTo(out, 0L, this.size);
|
|
}
|
|
|
|
public Buffer copyTo(OutputStream out, long offset, long byteCount) throws IOException {
|
|
if (out == null) {
|
|
throw new IllegalArgumentException("out == null");
|
|
}
|
|
Util.checkOffsetAndCount(this.size, offset, byteCount);
|
|
if (byteCount == 0L) {
|
|
return this;
|
|
}
|
|
Segment s = this.head;
|
|
while (offset >= (long)(s.limit - s.pos)) {
|
|
offset -= (long)(s.limit - s.pos);
|
|
s = s.next;
|
|
}
|
|
while (byteCount > 0L) {
|
|
int pos = (int)((long)s.pos + offset);
|
|
int toCopy = (int)Math.min((long)(s.limit - pos), byteCount);
|
|
out.write(s.data, pos, toCopy);
|
|
byteCount -= (long)toCopy;
|
|
offset = 0L;
|
|
s = s.next;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public Buffer copyTo(Buffer out, long offset, long byteCount) {
|
|
if (out == null) {
|
|
throw new IllegalArgumentException("out == null");
|
|
}
|
|
Util.checkOffsetAndCount(this.size, offset, byteCount);
|
|
if (byteCount == 0L) {
|
|
return this;
|
|
}
|
|
out.size += byteCount;
|
|
Segment s = this.head;
|
|
while (offset >= (long)(s.limit - s.pos)) {
|
|
offset -= (long)(s.limit - s.pos);
|
|
s = s.next;
|
|
}
|
|
while (byteCount > 0L) {
|
|
Segment copy = new Segment(s);
|
|
copy.pos = (int)((long)copy.pos + offset);
|
|
copy.limit = Math.min(copy.pos + (int)byteCount, copy.limit);
|
|
if (out.head == null) {
|
|
copy.next = copy.prev = copy;
|
|
out.head = copy.prev;
|
|
} else {
|
|
out.head.prev.push(copy);
|
|
}
|
|
byteCount -= (long)(copy.limit - copy.pos);
|
|
offset = 0L;
|
|
s = s.next;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public Buffer writeTo(OutputStream out) throws IOException {
|
|
return this.writeTo(out, this.size);
|
|
}
|
|
|
|
public Buffer writeTo(OutputStream out, long byteCount) throws IOException {
|
|
if (out == null) {
|
|
throw new IllegalArgumentException("out == null");
|
|
}
|
|
Util.checkOffsetAndCount(this.size, 0L, byteCount);
|
|
Segment s = this.head;
|
|
while (byteCount > 0L) {
|
|
int toCopy = (int)Math.min(byteCount, (long)(s.limit - s.pos));
|
|
out.write(s.data, s.pos, toCopy);
|
|
s.pos += toCopy;
|
|
this.size -= (long)toCopy;
|
|
byteCount -= (long)toCopy;
|
|
if (s.pos != s.limit) continue;
|
|
Segment toRecycle = s;
|
|
this.head = s = toRecycle.pop();
|
|
SegmentPool.recycle(toRecycle);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public Buffer readFrom(InputStream in) throws IOException {
|
|
this.readFrom(in, Long.MAX_VALUE, true);
|
|
return this;
|
|
}
|
|
|
|
public Buffer readFrom(InputStream in, long byteCount) throws IOException {
|
|
if (byteCount < 0L) {
|
|
throw new IllegalArgumentException("byteCount < 0: " + byteCount);
|
|
}
|
|
this.readFrom(in, byteCount, false);
|
|
return this;
|
|
}
|
|
|
|
private void readFrom(InputStream in, long byteCount, boolean forever) throws IOException {
|
|
if (in == null) {
|
|
throw new IllegalArgumentException("in == null");
|
|
}
|
|
while (byteCount > 0L || forever) {
|
|
Segment tail = this.writableSegment(1);
|
|
int maxToCopy = (int)Math.min(byteCount, (long)(2048 - tail.limit));
|
|
int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
|
|
if (bytesRead == -1) {
|
|
if (forever) {
|
|
return;
|
|
}
|
|
throw new EOFException();
|
|
}
|
|
tail.limit += bytesRead;
|
|
this.size += (long)bytesRead;
|
|
byteCount -= (long)bytesRead;
|
|
}
|
|
}
|
|
|
|
public long completeSegmentByteCount() {
|
|
long result = this.size;
|
|
if (result == 0L) {
|
|
return 0L;
|
|
}
|
|
Segment tail = this.head.prev;
|
|
if (tail.limit < 2048 && tail.owner) {
|
|
result -= (long)(tail.limit - tail.pos);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public byte readByte() {
|
|
if (this.size == 0L) {
|
|
throw new IllegalStateException("size == 0");
|
|
}
|
|
Segment segment = this.head;
|
|
int pos = segment.pos;
|
|
int limit = segment.limit;
|
|
byte[] data = segment.data;
|
|
byte b = data[pos++];
|
|
--this.size;
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
} else {
|
|
segment.pos = pos;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
public byte getByte(long pos) {
|
|
Util.checkOffsetAndCount(this.size, pos, 1L);
|
|
Segment s = this.head;
|
|
int segmentByteCount;
|
|
while (pos >= (long)(segmentByteCount = s.limit - s.pos)) {
|
|
pos -= (long)segmentByteCount;
|
|
s = s.next;
|
|
}
|
|
return s.data[s.pos + (int)pos];
|
|
}
|
|
|
|
@Override
|
|
public short readShort() {
|
|
if (this.size < 2L) {
|
|
throw new IllegalStateException("size < 2: " + this.size);
|
|
}
|
|
Segment segment = this.head;
|
|
int limit = segment.limit;
|
|
int pos = segment.pos;
|
|
if (limit - pos < 2) {
|
|
int s = (this.readByte() & 0xFF) << 8 | this.readByte() & 0xFF;
|
|
return (short)s;
|
|
}
|
|
byte[] data = segment.data;
|
|
int s = (data[pos++] & 0xFF) << 8 | data[pos++] & 0xFF;
|
|
this.size -= 2L;
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
} else {
|
|
segment.pos = pos;
|
|
}
|
|
return (short)s;
|
|
}
|
|
|
|
@Override
|
|
public int readInt() {
|
|
if (this.size < 4L) {
|
|
throw new IllegalStateException("size < 4: " + this.size);
|
|
}
|
|
Segment segment = this.head;
|
|
int limit = segment.limit;
|
|
int pos = segment.pos;
|
|
if (limit - pos < 4) {
|
|
return (this.readByte() & 0xFF) << 24 | (this.readByte() & 0xFF) << 16 | (this.readByte() & 0xFF) << 8 | this.readByte() & 0xFF;
|
|
}
|
|
byte[] data = segment.data;
|
|
int i = (data[pos++] & 0xFF) << 24 | (data[pos++] & 0xFF) << 16 | (data[pos++] & 0xFF) << 8 | data[pos++] & 0xFF;
|
|
this.size -= 4L;
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
} else {
|
|
segment.pos = pos;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
@Override
|
|
public long readLong() {
|
|
if (this.size < 8L) {
|
|
throw new IllegalStateException("size < 8: " + this.size);
|
|
}
|
|
Segment segment = this.head;
|
|
int limit = segment.limit;
|
|
int pos = segment.pos;
|
|
if (limit - pos < 8) {
|
|
return ((long)this.readInt() & 0xFFFFFFFFL) << 32 | (long)this.readInt() & 0xFFFFFFFFL;
|
|
}
|
|
byte[] data = segment.data;
|
|
long v = ((long)data[pos++] & 0xFFL) << 56 | ((long)data[pos++] & 0xFFL) << 48 | ((long)data[pos++] & 0xFFL) << 40 | ((long)data[pos++] & 0xFFL) << 32 | ((long)data[pos++] & 0xFFL) << 24 | ((long)data[pos++] & 0xFFL) << 16 | ((long)data[pos++] & 0xFFL) << 8 | (long)data[pos++] & 0xFFL;
|
|
this.size -= 8L;
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
} else {
|
|
segment.pos = pos;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
@Override
|
|
public short readShortLe() {
|
|
return Util.reverseBytesShort(this.readShort());
|
|
}
|
|
|
|
@Override
|
|
public int readIntLe() {
|
|
return Util.reverseBytesInt(this.readInt());
|
|
}
|
|
|
|
@Override
|
|
public long readLongLe() {
|
|
return Util.reverseBytesLong(this.readLong());
|
|
}
|
|
|
|
@Override
|
|
public long readDecimalLong() {
|
|
if (this.size == 0L) {
|
|
throw new IllegalStateException("size == 0");
|
|
}
|
|
long value = 0L;
|
|
int seen = 0;
|
|
boolean negative = false;
|
|
boolean done = false;
|
|
long overflowZone = -922337203685477580L;
|
|
long overflowDigit = -7L;
|
|
do {
|
|
Segment segment = this.head;
|
|
byte[] data = segment.data;
|
|
int pos = segment.pos;
|
|
int limit = segment.limit;
|
|
while (pos < limit) {
|
|
byte b = data[pos];
|
|
if (b >= 48 && b <= 57) {
|
|
int digit = 48 - b;
|
|
if (value < overflowZone || value == overflowZone && (long)digit < overflowDigit) {
|
|
Buffer buffer = new Buffer().writeDecimalLong(value).writeByte(b);
|
|
if (!negative) {
|
|
buffer.readByte();
|
|
}
|
|
throw new NumberFormatException("Number too large: " + buffer.readUtf8());
|
|
}
|
|
value *= 10L;
|
|
value += (long)digit;
|
|
} else if (b == 45 && seen == 0) {
|
|
negative = true;
|
|
--overflowDigit;
|
|
} else {
|
|
if (seen == 0) {
|
|
throw new NumberFormatException("Expected leading [0-9] or '-' character but was 0x" + Integer.toHexString(b));
|
|
}
|
|
done = true;
|
|
break;
|
|
}
|
|
++pos;
|
|
++seen;
|
|
}
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
continue;
|
|
}
|
|
segment.pos = pos;
|
|
} while (!done && this.head != null);
|
|
this.size -= (long)seen;
|
|
return negative ? value : -value;
|
|
}
|
|
|
|
@Override
|
|
public long readHexadecimalUnsignedLong() {
|
|
if (this.size == 0L) {
|
|
throw new IllegalStateException("size == 0");
|
|
}
|
|
long value = 0L;
|
|
int seen = 0;
|
|
boolean done = false;
|
|
do {
|
|
Segment segment = this.head;
|
|
byte[] data = segment.data;
|
|
int pos = segment.pos;
|
|
int limit = segment.limit;
|
|
while (pos < limit) {
|
|
int digit;
|
|
byte b = data[pos];
|
|
if (b >= 48 && b <= 57) {
|
|
digit = b - 48;
|
|
} else if (b >= 97 && b <= 102) {
|
|
digit = b - 97 + 10;
|
|
} else if (b >= 65 && b <= 70) {
|
|
digit = b - 65 + 10;
|
|
} else {
|
|
if (seen == 0) {
|
|
throw new NumberFormatException("Expected leading [0-9a-fA-F] character but was 0x" + Integer.toHexString(b));
|
|
}
|
|
done = true;
|
|
break;
|
|
}
|
|
if ((value & 0xF000000000000000L) != 0L) {
|
|
Buffer buffer = new Buffer().writeHexadecimalUnsignedLong(value).writeByte(b);
|
|
throw new NumberFormatException("Number too large: " + buffer.readUtf8());
|
|
}
|
|
value <<= 4;
|
|
value |= (long)digit;
|
|
++pos;
|
|
++seen;
|
|
}
|
|
if (pos == limit) {
|
|
this.head = segment.pop();
|
|
SegmentPool.recycle(segment);
|
|
continue;
|
|
}
|
|
segment.pos = pos;
|
|
} while (!done && this.head != null);
|
|
this.size -= (long)seen;
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public ByteString readByteString() {
|
|
return new ByteString(this.readByteArray());
|
|
}
|
|
|
|
@Override
|
|
public ByteString readByteString(long byteCount) throws EOFException {
|
|
return new ByteString(this.readByteArray(byteCount));
|
|
}
|
|
|
|
@Override
|
|
public void readFully(Buffer sink, long byteCount) throws EOFException {
|
|
if (this.size < byteCount) {
|
|
sink.write(this, this.size);
|
|
throw new EOFException();
|
|
}
|
|
sink.write(this, byteCount);
|
|
}
|
|
|
|
@Override
|
|
public long readAll(Sink sink) throws IOException {
|
|
long byteCount = this.size;
|
|
if (byteCount > 0L) {
|
|
sink.write(this, byteCount);
|
|
}
|
|
return byteCount;
|
|
}
|
|
|
|
@Override
|
|
public String readUtf8() {
|
|
try {
|
|
return this.readString(this.size, Util.UTF_8);
|
|
}
|
|
catch (EOFException e) {
|
|
throw new AssertionError((Object)e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String readUtf8(long byteCount) throws EOFException {
|
|
return this.readString(byteCount, Util.UTF_8);
|
|
}
|
|
|
|
@Override
|
|
public String readString(Charset charset) {
|
|
try {
|
|
return this.readString(this.size, charset);
|
|
}
|
|
catch (EOFException e) {
|
|
throw new AssertionError((Object)e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String readString(long byteCount, Charset charset) throws EOFException {
|
|
Util.checkOffsetAndCount(this.size, 0L, byteCount);
|
|
if (charset == null) {
|
|
throw new IllegalArgumentException("charset == null");
|
|
}
|
|
if (byteCount > Integer.MAX_VALUE) {
|
|
throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
|
|
}
|
|
if (byteCount == 0L) {
|
|
return "";
|
|
}
|
|
Segment s = this.head;
|
|
if ((long)s.pos + byteCount > (long)s.limit) {
|
|
return new String(this.readByteArray(byteCount), charset);
|
|
}
|
|
String result = new String(s.data, s.pos, (int)byteCount, charset);
|
|
s.pos = (int)((long)s.pos + byteCount);
|
|
this.size -= byteCount;
|
|
if (s.pos == s.limit) {
|
|
this.head = s.pop();
|
|
SegmentPool.recycle(s);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public String readUtf8Line() throws EOFException {
|
|
long newline = this.indexOf((byte)10);
|
|
if (newline == -1L) {
|
|
return this.size != 0L ? this.readUtf8(this.size) : null;
|
|
}
|
|
return this.readUtf8Line(newline);
|
|
}
|
|
|
|
@Override
|
|
public String readUtf8LineStrict() throws EOFException {
|
|
long newline = this.indexOf((byte)10);
|
|
if (newline == -1L) {
|
|
Buffer data = new Buffer();
|
|
this.copyTo(data, 0L, Math.min(32L, this.size));
|
|
throw new EOFException("\\n not found: size=" + this.size() + " content=" + data.readByteString().hex() + "...");
|
|
}
|
|
return this.readUtf8Line(newline);
|
|
}
|
|
|
|
String readUtf8Line(long newline) throws EOFException {
|
|
if (newline > 0L && this.getByte(newline - 1L) == 13) {
|
|
String result = this.readUtf8(newline - 1L);
|
|
this.skip(2L);
|
|
return result;
|
|
}
|
|
String result = this.readUtf8(newline);
|
|
this.skip(1L);
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public int readUtf8CodePoint() throws EOFException {
|
|
int min;
|
|
int byteCount;
|
|
int codePoint;
|
|
if (this.size == 0L) {
|
|
throw new EOFException();
|
|
}
|
|
byte b0 = this.getByte(0L);
|
|
if ((b0 & 0x80) == 0) {
|
|
codePoint = b0 & 0x7F;
|
|
byteCount = 1;
|
|
min = 0;
|
|
} else if ((b0 & 0xE0) == 192) {
|
|
codePoint = b0 & 0x1F;
|
|
byteCount = 2;
|
|
min = 128;
|
|
} else if ((b0 & 0xF0) == 224) {
|
|
codePoint = b0 & 0xF;
|
|
byteCount = 3;
|
|
min = 2048;
|
|
} else if ((b0 & 0xF8) == 240) {
|
|
codePoint = b0 & 7;
|
|
byteCount = 4;
|
|
min = 65536;
|
|
} else {
|
|
this.skip(1L);
|
|
return 65533;
|
|
}
|
|
if (this.size < (long)byteCount) {
|
|
throw new EOFException("size < " + byteCount + ": " + this.size + " (to read code point prefixed 0x" + Integer.toHexString(b0) + ")");
|
|
}
|
|
for (int i = 1; i < byteCount; ++i) {
|
|
byte b = this.getByte(i);
|
|
if ((b & 0xC0) == 128) {
|
|
codePoint <<= 6;
|
|
codePoint |= b & 0x3F;
|
|
continue;
|
|
}
|
|
this.skip(i);
|
|
return 65533;
|
|
}
|
|
this.skip(byteCount);
|
|
if (codePoint > 0x10FFFF) {
|
|
return 65533;
|
|
}
|
|
if (codePoint >= 55296 && codePoint <= 57343) {
|
|
return 65533;
|
|
}
|
|
if (codePoint < min) {
|
|
return 65533;
|
|
}
|
|
return codePoint;
|
|
}
|
|
|
|
@Override
|
|
public byte[] readByteArray() {
|
|
try {
|
|
return this.readByteArray(this.size);
|
|
}
|
|
catch (EOFException e) {
|
|
throw new AssertionError((Object)e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public byte[] readByteArray(long byteCount) throws EOFException {
|
|
Util.checkOffsetAndCount(this.size, 0L, byteCount);
|
|
if (byteCount > Integer.MAX_VALUE) {
|
|
throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
|
|
}
|
|
byte[] result = new byte[(int)byteCount];
|
|
this.readFully(result);
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public int read(byte[] sink) {
|
|
return this.read(sink, 0, sink.length);
|
|
}
|
|
|
|
@Override
|
|
public void readFully(byte[] sink) throws EOFException {
|
|
int read;
|
|
for (int offset = 0; offset < sink.length; offset += read) {
|
|
read = this.read(sink, offset, sink.length - offset);
|
|
if (read != -1) continue;
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int read(byte[] sink, int offset, int byteCount) {
|
|
Util.checkOffsetAndCount(sink.length, offset, byteCount);
|
|
Segment s = this.head;
|
|
if (s == null) {
|
|
return -1;
|
|
}
|
|
int toCopy = Math.min(byteCount, s.limit - s.pos);
|
|
System.arraycopy(s.data, s.pos, sink, offset, toCopy);
|
|
s.pos += toCopy;
|
|
this.size -= (long)toCopy;
|
|
if (s.pos == s.limit) {
|
|
this.head = s.pop();
|
|
SegmentPool.recycle(s);
|
|
}
|
|
return toCopy;
|
|
}
|
|
|
|
public void clear() {
|
|
try {
|
|
this.skip(this.size);
|
|
}
|
|
catch (EOFException e) {
|
|
throw new AssertionError((Object)e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void skip(long byteCount) throws EOFException {
|
|
while (byteCount > 0L) {
|
|
if (this.head == null) {
|
|
throw new EOFException();
|
|
}
|
|
int toSkip = (int)Math.min(byteCount, (long)(this.head.limit - this.head.pos));
|
|
this.size -= (long)toSkip;
|
|
byteCount -= (long)toSkip;
|
|
this.head.pos += toSkip;
|
|
if (this.head.pos != this.head.limit) continue;
|
|
Segment toRecycle = this.head;
|
|
this.head = toRecycle.pop();
|
|
SegmentPool.recycle(toRecycle);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Buffer write(ByteString byteString) {
|
|
if (byteString == null) {
|
|
throw new IllegalArgumentException("byteString == null");
|
|
}
|
|
byteString.write(this);
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeUtf8(String string) {
|
|
return this.writeUtf8(string, 0, string.length());
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeUtf8(String string, int beginIndex, int endIndex) {
|
|
if (string == null) {
|
|
throw new IllegalArgumentException("string == null");
|
|
}
|
|
if (beginIndex < 0) {
|
|
throw new IllegalAccessError("beginIndex < 0: " + beginIndex);
|
|
}
|
|
if (endIndex < beginIndex) {
|
|
throw new IllegalArgumentException("endIndex < beginIndex: " + endIndex + " < " + beginIndex);
|
|
}
|
|
if (endIndex > string.length()) {
|
|
throw new IllegalArgumentException("endIndex > string.length: " + endIndex + " > " + string.length());
|
|
}
|
|
int i = beginIndex;
|
|
while (i < endIndex) {
|
|
char low;
|
|
char c = string.charAt(i);
|
|
if (c < '\u0080') {
|
|
Segment tail = this.writableSegment(1);
|
|
byte[] data = tail.data;
|
|
int segmentOffset = tail.limit - i;
|
|
int runLimit = Math.min(endIndex, 2048 - segmentOffset);
|
|
data[segmentOffset + i++] = (byte)c;
|
|
while (i < runLimit && (c = string.charAt(i)) < '\u0080') {
|
|
data[segmentOffset + i++] = (byte)c;
|
|
}
|
|
int runSize = i + segmentOffset - tail.limit;
|
|
tail.limit += runSize;
|
|
this.size += (long)runSize;
|
|
continue;
|
|
}
|
|
if (c < '\u0800') {
|
|
this.writeByte(c >> 6 | 0xC0);
|
|
this.writeByte(c & 0x3F | 0x80);
|
|
++i;
|
|
continue;
|
|
}
|
|
if (c < '\ud800' || c > '\udfff') {
|
|
this.writeByte(c >> 12 | 0xE0);
|
|
this.writeByte(c >> 6 & 0x3F | 0x80);
|
|
this.writeByte(c & 0x3F | 0x80);
|
|
++i;
|
|
continue;
|
|
}
|
|
char c2 = low = i + 1 < endIndex ? string.charAt(i + 1) : (char)'\u0000';
|
|
if (c > '\udbff' || low < '\udc00' || low > '\udfff') {
|
|
this.writeByte(63);
|
|
++i;
|
|
continue;
|
|
}
|
|
int codePoint = 65536 + ((c & 0xFFFF27FF) << 10 | low & 0xFFFF23FF);
|
|
this.writeByte(codePoint >> 18 | 0xF0);
|
|
this.writeByte(codePoint >> 12 & 0x3F | 0x80);
|
|
this.writeByte(codePoint >> 6 & 0x3F | 0x80);
|
|
this.writeByte(codePoint & 0x3F | 0x80);
|
|
i += 2;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeUtf8CodePoint(int codePoint) {
|
|
if (codePoint < 128) {
|
|
this.writeByte(codePoint);
|
|
} else if (codePoint < 2048) {
|
|
this.writeByte(codePoint >> 6 | 0xC0);
|
|
this.writeByte(codePoint & 0x3F | 0x80);
|
|
} else if (codePoint < 65536) {
|
|
if (codePoint >= 55296 && codePoint <= 57343) {
|
|
throw new IllegalArgumentException("Unexpected code point: " + Integer.toHexString(codePoint));
|
|
}
|
|
this.writeByte(codePoint >> 12 | 0xE0);
|
|
this.writeByte(codePoint >> 6 & 0x3F | 0x80);
|
|
this.writeByte(codePoint & 0x3F | 0x80);
|
|
} else if (codePoint <= 0x10FFFF) {
|
|
this.writeByte(codePoint >> 18 | 0xF0);
|
|
this.writeByte(codePoint >> 12 & 0x3F | 0x80);
|
|
this.writeByte(codePoint >> 6 & 0x3F | 0x80);
|
|
this.writeByte(codePoint & 0x3F | 0x80);
|
|
} else {
|
|
throw new IllegalArgumentException("Unexpected code point: " + Integer.toHexString(codePoint));
|
|
}
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeString(String string, Charset charset) {
|
|
return this.writeString(string, 0, string.length(), charset);
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeString(String string, int beginIndex, int endIndex, Charset charset) {
|
|
if (string == null) {
|
|
throw new IllegalArgumentException("string == null");
|
|
}
|
|
if (beginIndex < 0) {
|
|
throw new IllegalAccessError("beginIndex < 0: " + beginIndex);
|
|
}
|
|
if (endIndex < beginIndex) {
|
|
throw new IllegalArgumentException("endIndex < beginIndex: " + endIndex + " < " + beginIndex);
|
|
}
|
|
if (endIndex > string.length()) {
|
|
throw new IllegalArgumentException("endIndex > string.length: " + endIndex + " > " + string.length());
|
|
}
|
|
if (charset == null) {
|
|
throw new IllegalArgumentException("charset == null");
|
|
}
|
|
if (charset.equals(Util.UTF_8)) {
|
|
return this.writeUtf8(string);
|
|
}
|
|
byte[] data = string.substring(beginIndex, endIndex).getBytes(charset);
|
|
return this.write(data, 0, data.length);
|
|
}
|
|
|
|
@Override
|
|
public Buffer write(byte[] source) {
|
|
if (source == null) {
|
|
throw new IllegalArgumentException("source == null");
|
|
}
|
|
return this.write(source, 0, source.length);
|
|
}
|
|
|
|
@Override
|
|
public Buffer write(byte[] source, int offset, int byteCount) {
|
|
if (source == null) {
|
|
throw new IllegalArgumentException("source == null");
|
|
}
|
|
Util.checkOffsetAndCount(source.length, offset, byteCount);
|
|
int limit = offset + byteCount;
|
|
while (offset < limit) {
|
|
Segment tail = this.writableSegment(1);
|
|
int toCopy = Math.min(limit - offset, 2048 - tail.limit);
|
|
System.arraycopy(source, offset, tail.data, tail.limit, toCopy);
|
|
offset += toCopy;
|
|
tail.limit += toCopy;
|
|
}
|
|
this.size += (long)byteCount;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public long writeAll(Source source) throws IOException {
|
|
long readCount;
|
|
if (source == null) {
|
|
throw new IllegalArgumentException("source == null");
|
|
}
|
|
long totalBytesRead = 0L;
|
|
while ((readCount = source.read(this, 2048L)) != -1L) {
|
|
totalBytesRead += readCount;
|
|
}
|
|
return totalBytesRead;
|
|
}
|
|
|
|
@Override
|
|
public BufferedSink write(Source source, long byteCount) throws IOException {
|
|
while (byteCount > 0L) {
|
|
long read = source.read(this, byteCount);
|
|
if (read == -1L) {
|
|
throw new EOFException();
|
|
}
|
|
byteCount -= read;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeByte(int b) {
|
|
Segment tail = this.writableSegment(1);
|
|
tail.data[tail.limit++] = (byte)b;
|
|
++this.size;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeShort(int s) {
|
|
Segment tail = this.writableSegment(2);
|
|
byte[] data = tail.data;
|
|
int limit = tail.limit;
|
|
data[limit++] = (byte)(s >>> 8 & 0xFF);
|
|
data[limit++] = (byte)(s & 0xFF);
|
|
tail.limit = limit;
|
|
this.size += 2L;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeShortLe(int s) {
|
|
return this.writeShort(Util.reverseBytesShort((short)s));
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeInt(int i) {
|
|
Segment tail = this.writableSegment(4);
|
|
byte[] data = tail.data;
|
|
int limit = tail.limit;
|
|
data[limit++] = (byte)(i >>> 24 & 0xFF);
|
|
data[limit++] = (byte)(i >>> 16 & 0xFF);
|
|
data[limit++] = (byte)(i >>> 8 & 0xFF);
|
|
data[limit++] = (byte)(i & 0xFF);
|
|
tail.limit = limit;
|
|
this.size += 4L;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeIntLe(int i) {
|
|
return this.writeInt(Util.reverseBytesInt(i));
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeLong(long v) {
|
|
Segment tail = this.writableSegment(8);
|
|
byte[] data = tail.data;
|
|
int limit = tail.limit;
|
|
data[limit++] = (byte)(v >>> 56 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 48 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 40 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 32 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 24 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 16 & 0xFFL);
|
|
data[limit++] = (byte)(v >>> 8 & 0xFFL);
|
|
data[limit++] = (byte)(v & 0xFFL);
|
|
tail.limit = limit;
|
|
this.size += 8L;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeLongLe(long v) {
|
|
return this.writeLong(Util.reverseBytesLong(v));
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeDecimalLong(long v) {
|
|
int width;
|
|
if (v == 0L) {
|
|
return this.writeByte(48);
|
|
}
|
|
boolean negative = false;
|
|
if (v < 0L) {
|
|
if ((v = -v) < 0L) {
|
|
return this.writeUtf8("-9223372036854775808");
|
|
}
|
|
negative = true;
|
|
}
|
|
int n = v < 100000000L ? (v < 10000L ? (v < 100L ? (v < 10L ? 1 : 2) : (v < 1000L ? 3 : 4)) : (v < 1000000L ? (v < 100000L ? 5 : 6) : (v < 10000000L ? 7 : 8))) : (v < 1000000000000L ? (v < 10000000000L ? (v < 1000000000L ? 9 : 10) : (v < 100000000000L ? 11 : 12)) : (v < 1000000000000000L ? (v < 10000000000000L ? 13 : (v < 100000000000000L ? 14 : 15)) : (v < 100000000000000000L ? (v < 10000000000000000L ? 16 : 17) : (width = v < 1000000000000000000L ? 18 : 19))));
|
|
if (negative) {
|
|
++width;
|
|
}
|
|
Segment tail = this.writableSegment(width);
|
|
byte[] data = tail.data;
|
|
int pos = tail.limit + width;
|
|
while (v != 0L) {
|
|
int digit = (int)(v % 10L);
|
|
data[--pos] = DIGITS[digit];
|
|
v /= 10L;
|
|
}
|
|
if (negative) {
|
|
data[--pos] = 45;
|
|
}
|
|
tail.limit += width;
|
|
this.size += (long)width;
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Buffer writeHexadecimalUnsignedLong(long v) {
|
|
if (v == 0L) {
|
|
return this.writeByte(48);
|
|
}
|
|
int width = Long.numberOfTrailingZeros(Long.highestOneBit(v)) / 4 + 1;
|
|
Segment tail = this.writableSegment(width);
|
|
byte[] data = tail.data;
|
|
int start = tail.limit;
|
|
for (int pos = tail.limit + width - 1; pos >= start; --pos) {
|
|
data[pos] = DIGITS[(int)(v & 0xFL)];
|
|
v >>>= 4;
|
|
}
|
|
tail.limit += width;
|
|
this.size += (long)width;
|
|
return this;
|
|
}
|
|
|
|
Segment writableSegment(int minimumCapacity) {
|
|
if (minimumCapacity < 1 || minimumCapacity > 2048) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
if (this.head == null) {
|
|
this.head.next = this.head.prev = (this.head = SegmentPool.take());
|
|
return this.head.prev;
|
|
}
|
|
Segment tail = this.head.prev;
|
|
if (tail.limit + minimumCapacity > 2048 || !tail.owner) {
|
|
tail = tail.push(SegmentPool.take());
|
|
}
|
|
return tail;
|
|
}
|
|
|
|
@Override
|
|
public void write(Buffer source, long byteCount) {
|
|
if (source == null) {
|
|
throw new IllegalArgumentException("source == null");
|
|
}
|
|
if (source == this) {
|
|
throw new IllegalArgumentException("source == this");
|
|
}
|
|
Util.checkOffsetAndCount(source.size, 0L, byteCount);
|
|
while (byteCount > 0L) {
|
|
if (byteCount < (long)(source.head.limit - source.head.pos)) {
|
|
Segment tail;
|
|
Segment segment = tail = this.head != null ? this.head.prev : null;
|
|
if (tail != null && tail.owner && byteCount + (long)tail.limit - (long)(tail.shared ? 0 : tail.pos) <= 2048L) {
|
|
source.head.writeTo(tail, (int)byteCount);
|
|
source.size -= byteCount;
|
|
this.size += byteCount;
|
|
return;
|
|
}
|
|
source.head = source.head.split((int)byteCount);
|
|
}
|
|
Segment segmentToMove = source.head;
|
|
long movedByteCount = segmentToMove.limit - segmentToMove.pos;
|
|
source.head = segmentToMove.pop();
|
|
if (this.head == null) {
|
|
this.head.next = this.head.prev = (this.head = segmentToMove);
|
|
} else {
|
|
Segment tail = this.head.prev;
|
|
tail = tail.push(segmentToMove);
|
|
tail.compact();
|
|
}
|
|
source.size -= movedByteCount;
|
|
this.size += movedByteCount;
|
|
byteCount -= movedByteCount;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long read(Buffer sink, long byteCount) {
|
|
if (sink == null) {
|
|
throw new IllegalArgumentException("sink == null");
|
|
}
|
|
if (byteCount < 0L) {
|
|
throw new IllegalArgumentException("byteCount < 0: " + byteCount);
|
|
}
|
|
if (this.size == 0L) {
|
|
return -1L;
|
|
}
|
|
if (byteCount > this.size) {
|
|
byteCount = this.size;
|
|
}
|
|
sink.write(this, byteCount);
|
|
return byteCount;
|
|
}
|
|
|
|
@Override
|
|
public long indexOf(byte b) {
|
|
return this.indexOf(b, 0L);
|
|
}
|
|
|
|
@Override
|
|
public long indexOf(byte b, long fromIndex) {
|
|
if (fromIndex < 0L) {
|
|
throw new IllegalArgumentException("fromIndex < 0");
|
|
}
|
|
Segment s = this.head;
|
|
if (s == null) {
|
|
return -1L;
|
|
}
|
|
long offset = 0L;
|
|
do {
|
|
int segmentByteCount;
|
|
if (fromIndex >= (long)(segmentByteCount = s.limit - s.pos)) {
|
|
fromIndex -= (long)segmentByteCount;
|
|
} else {
|
|
byte[] data = s.data;
|
|
int limit = s.limit;
|
|
for (int pos = (int)((long)s.pos + fromIndex); pos < limit; ++pos) {
|
|
if (data[pos] != b) continue;
|
|
return offset + (long)pos - (long)s.pos;
|
|
}
|
|
fromIndex = 0L;
|
|
}
|
|
offset += (long)segmentByteCount;
|
|
} while ((s = s.next) != this.head);
|
|
return -1L;
|
|
}
|
|
|
|
@Override
|
|
public long indexOf(ByteString bytes) throws IOException {
|
|
return this.indexOf(bytes, 0L);
|
|
}
|
|
|
|
@Override
|
|
public long indexOf(ByteString bytes, long fromIndex) throws IOException {
|
|
if (bytes.size() == 0) {
|
|
throw new IllegalArgumentException("bytes is empty");
|
|
}
|
|
while ((fromIndex = this.indexOf(bytes.getByte(0), fromIndex)) != -1L) {
|
|
if (this.rangeEquals(fromIndex, bytes)) {
|
|
return fromIndex;
|
|
}
|
|
++fromIndex;
|
|
}
|
|
return -1L;
|
|
}
|
|
|
|
@Override
|
|
public long indexOfElement(ByteString targetBytes) {
|
|
return this.indexOfElement(targetBytes, 0L);
|
|
}
|
|
|
|
@Override
|
|
public long indexOfElement(ByteString targetBytes, long fromIndex) {
|
|
if (fromIndex < 0L) {
|
|
throw new IllegalArgumentException("fromIndex < 0");
|
|
}
|
|
Segment s = this.head;
|
|
if (s == null) {
|
|
return -1L;
|
|
}
|
|
long offset = 0L;
|
|
byte[] toFind = targetBytes.toByteArray();
|
|
do {
|
|
int segmentByteCount;
|
|
if (fromIndex >= (long)(segmentByteCount = s.limit - s.pos)) {
|
|
fromIndex -= (long)segmentByteCount;
|
|
} else {
|
|
byte[] data = s.data;
|
|
long limit = s.limit;
|
|
for (long pos = (long)s.pos + fromIndex; pos < limit; ++pos) {
|
|
byte b = data[(int)pos];
|
|
for (byte targetByte : toFind) {
|
|
if (b != targetByte) continue;
|
|
return offset + pos - (long)s.pos;
|
|
}
|
|
}
|
|
fromIndex = 0L;
|
|
}
|
|
offset += (long)segmentByteCount;
|
|
} while ((s = s.next) != this.head);
|
|
return -1L;
|
|
}
|
|
|
|
boolean rangeEquals(long offset, ByteString bytes) {
|
|
int byteCount = bytes.size();
|
|
if (this.size - offset < (long)byteCount) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < byteCount; ++i) {
|
|
if (this.getByte(offset + (long)i) == bytes.getByte(i)) continue;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void flush() {
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
}
|
|
|
|
@Override
|
|
public Timeout timeout() {
|
|
return Timeout.NONE;
|
|
}
|
|
|
|
List<Integer> segmentSizes() {
|
|
if (this.head == null) {
|
|
return Collections.emptyList();
|
|
}
|
|
ArrayList<Integer> result = new ArrayList<Integer>();
|
|
result.add(this.head.limit - this.head.pos);
|
|
Segment s = this.head.next;
|
|
while (s != this.head) {
|
|
result.add(s.limit - s.pos);
|
|
s = s.next;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public boolean equals(Object o) {
|
|
long count;
|
|
if (this == o) {
|
|
return true;
|
|
}
|
|
if (!(o instanceof Buffer)) {
|
|
return false;
|
|
}
|
|
Buffer that = (Buffer)o;
|
|
if (this.size != that.size) {
|
|
return false;
|
|
}
|
|
if (this.size == 0L) {
|
|
return true;
|
|
}
|
|
Segment sa = this.head;
|
|
Segment sb = that.head;
|
|
int posA = sa.pos;
|
|
int posB = sb.pos;
|
|
for (long pos = 0L; pos < this.size; pos += count) {
|
|
count = Math.min(sa.limit - posA, sb.limit - posB);
|
|
int i = 0;
|
|
while ((long)i < count) {
|
|
if (sa.data[posA++] != sb.data[posB++]) {
|
|
return false;
|
|
}
|
|
++i;
|
|
}
|
|
if (posA == sa.limit) {
|
|
sa = sa.next;
|
|
posA = sa.pos;
|
|
}
|
|
if (posB != sb.limit) continue;
|
|
sb = sb.next;
|
|
posB = sb.pos;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public int hashCode() {
|
|
Segment s = this.head;
|
|
if (s == null) {
|
|
return 0;
|
|
}
|
|
int result = 1;
|
|
do {
|
|
int limit = s.limit;
|
|
for (int pos = s.pos; pos < limit; ++pos) {
|
|
result = 31 * result + s.data[pos];
|
|
}
|
|
} while ((s = s.next) != this.head);
|
|
return result;
|
|
}
|
|
|
|
public String toString() {
|
|
if (this.size == 0L) {
|
|
return "Buffer[size=0]";
|
|
}
|
|
if (this.size <= 16L) {
|
|
ByteString data = this.clone().readByteString();
|
|
return String.format("Buffer[size=%s data=%s]", this.size, data.hex());
|
|
}
|
|
try {
|
|
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
|
md5.update(this.head.data, this.head.pos, this.head.limit - this.head.pos);
|
|
Segment s = this.head.next;
|
|
while (s != this.head) {
|
|
md5.update(s.data, s.pos, s.limit - s.pos);
|
|
s = s.next;
|
|
}
|
|
return String.format("Buffer[size=%s md5=%s]", this.size, ByteString.of(md5.digest()).hex());
|
|
}
|
|
catch (NoSuchAlgorithmException e) {
|
|
throw new AssertionError();
|
|
}
|
|
}
|
|
|
|
public Buffer clone() {
|
|
Buffer result = new Buffer();
|
|
if (this.size == 0L) {
|
|
return result;
|
|
}
|
|
result.head.next = result.head.prev = (result.head = new Segment(this.head));
|
|
Segment s = this.head.next;
|
|
while (s != this.head) {
|
|
result.head.prev.push(new Segment(s));
|
|
s = s.next;
|
|
}
|
|
result.size = this.size;
|
|
return result;
|
|
}
|
|
|
|
public ByteString snapshot() {
|
|
if (this.size > Integer.MAX_VALUE) {
|
|
throw new IllegalArgumentException("size > Integer.MAX_VALUE: " + this.size);
|
|
}
|
|
return this.snapshot((int)this.size);
|
|
}
|
|
|
|
public ByteString snapshot(int byteCount) {
|
|
if (byteCount == 0) {
|
|
return ByteString.EMPTY;
|
|
}
|
|
return new SegmentedByteString(this, byteCount);
|
|
}
|
|
}
|
|
|