Home | History | Annotate | Download | only in okio
      1 /*
      2  * Copyright (C) 2014 Square, Inc.
      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  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package okio;
     17 
     18 import java.io.EOFException;
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.io.OutputStream;
     22 import java.nio.charset.Charset;
     23 import java.security.MessageDigest;
     24 import java.security.NoSuchAlgorithmException;
     25 import java.util.ArrayList;
     26 import java.util.Collections;
     27 import java.util.List;
     28 
     29 import static okio.Util.checkOffsetAndCount;
     30 import static okio.Util.reverseBytesLong;
     31 
     32 /**
     33  * A collection of bytes in memory.
     34  *
     35  * <p><strong>Moving data from one buffer to another is fast.</strong> Instead
     36  * of copying bytes from one place in memory to another, this class just changes
     37  * ownership of the underlying byte arrays.
     38  *
     39  * <p><strong>This buffer grows with your data.</strong> Just like ArrayList,
     40  * each buffer starts small. It consumes only the memory it needs to.
     41  *
     42  * <p><strong>This buffer pools its byte arrays.</strong> When you allocate a
     43  * byte array in Java, the runtime must zero-fill the requested array before
     44  * returning it to you. Even if you're going to write over that space anyway.
     45  * This class avoids zero-fill and GC churn by pooling byte arrays.
     46  */
     47 public final class Buffer implements BufferedSource, BufferedSink, Cloneable {
     48   private static final byte[] DIGITS =
     49       { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
     50   static final int REPLACEMENT_CHARACTER = '\ufffd';
     51 
     52   Segment head;
     53   long size;
     54 
     55   public Buffer() {
     56   }
     57 
     58   /** Returns the number of bytes currently in this buffer. */
     59   public long size() {
     60     return size;
     61   }
     62 
     63   @Override public Buffer buffer() {
     64     return this;
     65   }
     66 
     67   @Override public OutputStream outputStream() {
     68     return new OutputStream() {
     69       @Override public void write(int b) {
     70         writeByte((byte) b);
     71       }
     72 
     73       @Override public void write(byte[] data, int offset, int byteCount) {
     74         Buffer.this.write(data, offset, byteCount);
     75       }
     76 
     77       @Override public void flush() {
     78       }
     79 
     80       @Override public void close() {
     81       }
     82 
     83       @Override public String toString() {
     84         return this + ".outputStream()";
     85       }
     86     };
     87   }
     88 
     89   @Override public Buffer emitCompleteSegments() {
     90     return this; // Nowhere to emit to!
     91   }
     92 
     93   @Override public BufferedSink emit() {
     94     return this; // Nowhere to emit to!
     95   }
     96 
     97   @Override public boolean exhausted() {
     98     return size == 0;
     99   }
    100 
    101   @Override public void require(long byteCount) throws EOFException {
    102     if (size < byteCount) throw new EOFException();
    103   }
    104 
    105   @Override public boolean request(long byteCount) {
    106     return size >= byteCount;
    107   }
    108 
    109   @Override public InputStream inputStream() {
    110     return new InputStream() {
    111       @Override public int read() {
    112         if (size > 0) return readByte() & 0xff;
    113         return -1;
    114       }
    115 
    116       @Override public int read(byte[] sink, int offset, int byteCount) {
    117         return Buffer.this.read(sink, offset, byteCount);
    118       }
    119 
    120       @Override public int available() {
    121         return (int) Math.min(size, Integer.MAX_VALUE);
    122       }
    123 
    124       @Override public void close() {
    125       }
    126 
    127       @Override public String toString() {
    128         return Buffer.this + ".inputStream()";
    129       }
    130     };
    131   }
    132 
    133   /** Copy the contents of this to {@code out}. */
    134   public Buffer copyTo(OutputStream out) throws IOException {
    135     return copyTo(out, 0, size);
    136   }
    137 
    138   /**
    139    * Copy {@code byteCount} bytes from this, starting at {@code offset}, to
    140    * {@code out}.
    141    */
    142   public Buffer copyTo(OutputStream out, long offset, long byteCount) throws IOException {
    143     if (out == null) throw new IllegalArgumentException("out == null");
    144     checkOffsetAndCount(size, offset, byteCount);
    145     if (byteCount == 0) return this;
    146 
    147     // Skip segments that we aren't copying from.
    148     Segment s = head;
    149     for (; offset >= (s.limit - s.pos); s = s.next) {
    150       offset -= (s.limit - s.pos);
    151     }
    152 
    153     // Copy from one segment at a time.
    154     for (; byteCount > 0; s = s.next) {
    155       int pos = (int) (s.pos + offset);
    156       int toCopy = (int) Math.min(s.limit - pos, byteCount);
    157       out.write(s.data, pos, toCopy);
    158       byteCount -= toCopy;
    159       offset = 0;
    160     }
    161 
    162     return this;
    163   }
    164 
    165   /** Copy {@code byteCount} bytes from this, starting at {@code offset}, to {@code out}. */
    166   public Buffer copyTo(Buffer out, long offset, long byteCount) {
    167     if (out == null) throw new IllegalArgumentException("out == null");
    168     checkOffsetAndCount(size, offset, byteCount);
    169     if (byteCount == 0) return this;
    170 
    171     out.size += byteCount;
    172 
    173     // Skip segments that we aren't copying from.
    174     Segment s = head;
    175     for (; offset >= (s.limit - s.pos); s = s.next) {
    176       offset -= (s.limit - s.pos);
    177     }
    178 
    179     // Copy one segment at a time.
    180     for (; byteCount > 0; s = s.next) {
    181       Segment copy = new Segment(s);
    182       copy.pos += offset;
    183       copy.limit = Math.min(copy.pos + (int) byteCount, copy.limit);
    184       if (out.head == null) {
    185         out.head = copy.next = copy.prev = copy;
    186       } else {
    187         out.head.prev.push(copy);
    188       }
    189       byteCount -= copy.limit - copy.pos;
    190       offset = 0;
    191     }
    192 
    193     return this;
    194   }
    195 
    196   /** Write the contents of this to {@code out}. */
    197   public Buffer writeTo(OutputStream out) throws IOException {
    198     return writeTo(out, size);
    199   }
    200 
    201   /** Write {@code byteCount} bytes from this to {@code out}. */
    202   public Buffer writeTo(OutputStream out, long byteCount) throws IOException {
    203     if (out == null) throw new IllegalArgumentException("out == null");
    204     checkOffsetAndCount(size, 0, byteCount);
    205 
    206     Segment s = head;
    207     while (byteCount > 0) {
    208       int toCopy = (int) Math.min(byteCount, s.limit - s.pos);
    209       out.write(s.data, s.pos, toCopy);
    210 
    211       s.pos += toCopy;
    212       size -= toCopy;
    213       byteCount -= toCopy;
    214 
    215       if (s.pos == s.limit) {
    216         Segment toRecycle = s;
    217         head = s = toRecycle.pop();
    218         SegmentPool.recycle(toRecycle);
    219       }
    220     }
    221 
    222     return this;
    223   }
    224 
    225   /** Read and exhaust bytes from {@code in} to this. */
    226   public Buffer readFrom(InputStream in) throws IOException {
    227     readFrom(in, Long.MAX_VALUE, true);
    228     return this;
    229   }
    230 
    231   /** Read {@code byteCount} bytes from {@code in} to this. */
    232   public Buffer readFrom(InputStream in, long byteCount) throws IOException {
    233     if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
    234     readFrom(in, byteCount, false);
    235     return this;
    236   }
    237 
    238   private void readFrom(InputStream in, long byteCount, boolean forever) throws IOException {
    239     if (in == null) throw new IllegalArgumentException("in == null");
    240     while (byteCount > 0 || forever) {
    241       Segment tail = writableSegment(1);
    242       int maxToCopy = (int) Math.min(byteCount, Segment.SIZE - tail.limit);
    243       int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
    244       if (bytesRead == -1) {
    245         if (forever) return;
    246         throw new EOFException();
    247       }
    248       tail.limit += bytesRead;
    249       size += bytesRead;
    250       byteCount -= bytesRead;
    251     }
    252   }
    253 
    254   /**
    255    * Returns the number of bytes in segments that are not writable. This is the
    256    * number of bytes that can be flushed immediately to an underlying sink
    257    * without harming throughput.
    258    */
    259   public long completeSegmentByteCount() {
    260     long result = size;
    261     if (result == 0) return 0;
    262 
    263     // Omit the tail if it's still writable.
    264     Segment tail = head.prev;
    265     if (tail.limit < Segment.SIZE && tail.owner) {
    266       result -= tail.limit - tail.pos;
    267     }
    268 
    269     return result;
    270   }
    271 
    272   @Override public byte readByte() {
    273     if (size == 0) throw new IllegalStateException("size == 0");
    274 
    275     Segment segment = head;
    276     int pos = segment.pos;
    277     int limit = segment.limit;
    278 
    279     byte[] data = segment.data;
    280     byte b = data[pos++];
    281     size -= 1;
    282 
    283     if (pos == limit) {
    284       head = segment.pop();
    285       SegmentPool.recycle(segment);
    286     } else {
    287       segment.pos = pos;
    288     }
    289 
    290     return b;
    291   }
    292 
    293   /** Returns the byte at {@code pos}. */
    294   public byte getByte(long pos) {
    295     checkOffsetAndCount(size, pos, 1);
    296     for (Segment s = head; true; s = s.next) {
    297       int segmentByteCount = s.limit - s.pos;
    298       if (pos < segmentByteCount) return s.data[s.pos + (int) pos];
    299       pos -= segmentByteCount;
    300     }
    301   }
    302 
    303   @Override public short readShort() {
    304     if (size < 2) throw new IllegalStateException("size < 2: " + size);
    305 
    306     Segment segment = head;
    307     int pos = segment.pos;
    308     int limit = segment.limit;
    309 
    310     // If the short is split across multiple segments, delegate to readByte().
    311     if (limit - pos < 2) {
    312       int s = (readByte() & 0xff) << 8
    313           |   (readByte() & 0xff);
    314       return (short) s;
    315     }
    316 
    317     byte[] data = segment.data;
    318     int s = (data[pos++] & 0xff) << 8
    319         |   (data[pos++] & 0xff);
    320     size -= 2;
    321 
    322     if (pos == limit) {
    323       head = segment.pop();
    324       SegmentPool.recycle(segment);
    325     } else {
    326       segment.pos = pos;
    327     }
    328 
    329     return (short) s;
    330   }
    331 
    332   @Override public int readInt() {
    333     if (size < 4) throw new IllegalStateException("size < 4: " + size);
    334 
    335     Segment segment = head;
    336     int pos = segment.pos;
    337     int limit = segment.limit;
    338 
    339     // If the int is split across multiple segments, delegate to readByte().
    340     if (limit - pos < 4) {
    341       return (readByte() & 0xff) << 24
    342           |  (readByte() & 0xff) << 16
    343           |  (readByte() & 0xff) <<  8
    344           |  (readByte() & 0xff);
    345     }
    346 
    347     byte[] data = segment.data;
    348     int i = (data[pos++] & 0xff) << 24
    349         |   (data[pos++] & 0xff) << 16
    350         |   (data[pos++] & 0xff) <<  8
    351         |   (data[pos++] & 0xff);
    352     size -= 4;
    353 
    354     if (pos == limit) {
    355       head = segment.pop();
    356       SegmentPool.recycle(segment);
    357     } else {
    358       segment.pos = pos;
    359     }
    360 
    361     return i;
    362   }
    363 
    364   @Override public long readLong() {
    365     if (size < 8) throw new IllegalStateException("size < 8: " + size);
    366 
    367     Segment segment = head;
    368     int pos = segment.pos;
    369     int limit = segment.limit;
    370 
    371     // If the long is split across multiple segments, delegate to readInt().
    372     if (limit - pos < 8) {
    373       return (readInt() & 0xffffffffL) << 32
    374           |  (readInt() & 0xffffffffL);
    375     }
    376 
    377     byte[] data = segment.data;
    378     long v = (data[pos++] & 0xffL) << 56
    379         |    (data[pos++] & 0xffL) << 48
    380         |    (data[pos++] & 0xffL) << 40
    381         |    (data[pos++] & 0xffL) << 32
    382         |    (data[pos++] & 0xffL) << 24
    383         |    (data[pos++] & 0xffL) << 16
    384         |    (data[pos++] & 0xffL) <<  8
    385         |    (data[pos++] & 0xffL);
    386     size -= 8;
    387 
    388     if (pos == limit) {
    389       head = segment.pop();
    390       SegmentPool.recycle(segment);
    391     } else {
    392       segment.pos = pos;
    393     }
    394 
    395     return v;
    396   }
    397 
    398   @Override public short readShortLe() {
    399     return Util.reverseBytesShort(readShort());
    400   }
    401 
    402   @Override public int readIntLe() {
    403     return Util.reverseBytesInt(readInt());
    404   }
    405 
    406   @Override public long readLongLe() {
    407     return Util.reverseBytesLong(readLong());
    408   }
    409 
    410   @Override public long readDecimalLong() {
    411     if (size == 0) throw new IllegalStateException("size == 0");
    412 
    413     // This value is always built negatively in order to accommodate Long.MIN_VALUE.
    414     long value = 0;
    415     int seen = 0;
    416     boolean negative = false;
    417     boolean done = false;
    418 
    419     long overflowZone = Long.MIN_VALUE / 10;
    420     long overflowDigit = (Long.MIN_VALUE % 10) + 1;
    421 
    422     do {
    423       Segment segment = head;
    424 
    425       byte[] data = segment.data;
    426       int pos = segment.pos;
    427       int limit = segment.limit;
    428 
    429       for (; pos < limit; pos++, seen++) {
    430         byte b = data[pos];
    431         if (b >= '0' && b <= '9') {
    432           int digit = '0' - b;
    433 
    434           // Detect when the digit would cause an overflow.
    435           if (value < overflowZone || value == overflowZone && digit < overflowDigit) {
    436             Buffer buffer = new Buffer().writeDecimalLong(value).writeByte(b);
    437             if (!negative) buffer.readByte(); // Skip negative sign.
    438             throw new NumberFormatException("Number too large: " + buffer.readUtf8());
    439           }
    440           value *= 10;
    441           value += digit;
    442         } else if (b == '-' && seen == 0) {
    443           negative = true;
    444           overflowDigit -= 1;
    445         } else {
    446           if (seen == 0) {
    447             throw new NumberFormatException(
    448                 "Expected leading [0-9] or '-' character but was 0x" + Integer.toHexString(b));
    449           }
    450           // Set a flag to stop iteration. We still need to run through segment updating below.
    451           done = true;
    452           break;
    453         }
    454       }
    455 
    456       if (pos == limit) {
    457         head = segment.pop();
    458         SegmentPool.recycle(segment);
    459       } else {
    460         segment.pos = pos;
    461       }
    462     } while (!done && head != null);
    463 
    464     size -= seen;
    465     return negative ? value : -value;
    466   }
    467 
    468   @Override public long readHexadecimalUnsignedLong() {
    469     if (size == 0) throw new IllegalStateException("size == 0");
    470 
    471     long value = 0;
    472     int seen = 0;
    473     boolean done = false;
    474 
    475     do {
    476       Segment segment = head;
    477 
    478       byte[] data = segment.data;
    479       int pos = segment.pos;
    480       int limit = segment.limit;
    481 
    482       for (; pos < limit; pos++, seen++) {
    483         int digit;
    484 
    485         byte b = data[pos];
    486         if (b >= '0' && b <= '9') {
    487           digit = b - '0';
    488         } else if (b >= 'a' && b <= 'f') {
    489           digit = b - 'a' + 10;
    490         } else if (b >= 'A' && b <= 'F') {
    491           digit = b - 'A' + 10; // We never write uppercase, but we support reading it.
    492         } else {
    493           if (seen == 0) {
    494             throw new NumberFormatException(
    495                 "Expected leading [0-9a-fA-F] character but was 0x" + Integer.toHexString(b));
    496           }
    497           // Set a flag to stop iteration. We still need to run through segment updating below.
    498           done = true;
    499           break;
    500         }
    501 
    502         // Detect when the shift will overflow.
    503         if ((value & 0xf000000000000000L) != 0) {
    504           Buffer buffer = new Buffer().writeHexadecimalUnsignedLong(value).writeByte(b);
    505           throw new NumberFormatException("Number too large: " + buffer.readUtf8());
    506         }
    507 
    508         value <<= 4;
    509         value |= digit;
    510       }
    511 
    512       if (pos == limit) {
    513         head = segment.pop();
    514         SegmentPool.recycle(segment);
    515       } else {
    516         segment.pos = pos;
    517       }
    518     } while (!done && head != null);
    519 
    520     size -= seen;
    521     return value;
    522   }
    523 
    524   @Override public ByteString readByteString() {
    525     return new ByteString(readByteArray());
    526   }
    527 
    528   @Override public ByteString readByteString(long byteCount) throws EOFException {
    529     return new ByteString(readByteArray(byteCount));
    530   }
    531 
    532   @Override public void readFully(Buffer sink, long byteCount) throws EOFException {
    533     if (size < byteCount) {
    534       sink.write(this, size); // Exhaust ourselves.
    535       throw new EOFException();
    536     }
    537     sink.write(this, byteCount);
    538   }
    539 
    540   @Override public long readAll(Sink sink) throws IOException {
    541     long byteCount = size;
    542     if (byteCount > 0) {
    543       sink.write(this, byteCount);
    544     }
    545     return byteCount;
    546   }
    547 
    548   @Override public String readUtf8() {
    549     try {
    550       return readString(size, Util.UTF_8);
    551     } catch (EOFException e) {
    552       throw new AssertionError(e);
    553     }
    554   }
    555 
    556   @Override public String readUtf8(long byteCount) throws EOFException {
    557     return readString(byteCount, Util.UTF_8);
    558   }
    559 
    560   @Override public String readString(Charset charset) {
    561     try {
    562       return readString(size, charset);
    563     } catch (EOFException e) {
    564       throw new AssertionError(e);
    565     }
    566   }
    567 
    568   @Override public String readString(long byteCount, Charset charset) throws EOFException {
    569     checkOffsetAndCount(size, 0, byteCount);
    570     if (charset == null) throw new IllegalArgumentException("charset == null");
    571     if (byteCount > Integer.MAX_VALUE) {
    572       throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
    573     }
    574     if (byteCount == 0) return "";
    575 
    576     Segment s = head;
    577     if (s.pos + byteCount > s.limit) {
    578       // If the string spans multiple segments, delegate to readBytes().
    579       return new String(readByteArray(byteCount), charset);
    580     }
    581 
    582     String result = new String(s.data, s.pos, (int) byteCount, charset);
    583     s.pos += byteCount;
    584     size -= byteCount;
    585 
    586     if (s.pos == s.limit) {
    587       head = s.pop();
    588       SegmentPool.recycle(s);
    589     }
    590 
    591     return result;
    592   }
    593 
    594   @Override public String readUtf8Line() throws EOFException {
    595     long newline = indexOf((byte) '\n');
    596 
    597     if (newline == -1) {
    598       return size != 0 ? readUtf8(size) : null;
    599     }
    600 
    601     return readUtf8Line(newline);
    602   }
    603 
    604   @Override public String readUtf8LineStrict() throws EOFException {
    605     long newline = indexOf((byte) '\n');
    606     if (newline == -1) {
    607       Buffer data = new Buffer();
    608       copyTo(data, 0, Math.min(32, size));
    609       throw new EOFException("\\n not found: size=" + size()
    610           + " content=" + data.readByteString().hex() + "...");
    611     }
    612     return readUtf8Line(newline);
    613   }
    614 
    615   String readUtf8Line(long newline) throws EOFException {
    616     if (newline > 0 && getByte(newline - 1) == '\r') {
    617       // Read everything until '\r\n', then skip the '\r\n'.
    618       String result = readUtf8((newline - 1));
    619       skip(2);
    620       return result;
    621 
    622     } else {
    623       // Read everything until '\n', then skip the '\n'.
    624       String result = readUtf8(newline);
    625       skip(1);
    626       return result;
    627     }
    628   }
    629 
    630   @Override public int readUtf8CodePoint() throws EOFException {
    631     if (size == 0) throw new EOFException();
    632 
    633     byte b0 = getByte(0);
    634     int codePoint;
    635     int byteCount;
    636     int min;
    637 
    638     if ((b0 & 0x80) == 0) {
    639       // 0xxxxxxx.
    640       codePoint = b0 & 0x7f;
    641       byteCount = 1; // 7 bits (ASCII).
    642       min = 0x0;
    643 
    644     } else if ((b0 & 0xe0) == 0xc0) {
    645       // 0x110xxxxx
    646       codePoint = b0 & 0x1f;
    647       byteCount = 2; // 11 bits (5 + 6).
    648       min = 0x80;
    649 
    650     } else if ((b0 & 0xf0) == 0xe0) {
    651       // 0x1110xxxx
    652       codePoint = b0 & 0x0f;
    653       byteCount = 3; // 16 bits (4 + 6 + 6).
    654       min = 0x800;
    655 
    656     } else if ((b0 & 0xf8) == 0xf0) {
    657       // 0x11110xxx
    658       codePoint = b0 & 0x07;
    659       byteCount = 4; // 21 bits (3 + 6 + 6 + 6).
    660       min = 0x10000;
    661 
    662     } else {
    663       // We expected the first byte of a code point but got something else.
    664       skip(1);
    665       return REPLACEMENT_CHARACTER;
    666     }
    667 
    668     if (size < byteCount) {
    669       throw new EOFException("size < " + byteCount + ": " + size
    670           + " (to read code point prefixed 0x" + Integer.toHexString(b0) + ")");
    671     }
    672 
    673     // Read the continuation bytes. If we encounter a non-continuation byte, the sequence consumed
    674     // thus far is truncated and is decoded as the replacement character. That non-continuation byte
    675     // is left in the stream for processing by the next call to readUtf8CodePoint().
    676     for (int i = 1; i < byteCount; i++) {
    677       byte b = getByte(i);
    678       if ((b & 0xc0) == 0x80) {
    679         // 0x10xxxxxx
    680         codePoint <<= 6;
    681         codePoint |= b & 0x3f;
    682       } else {
    683         skip(i);
    684         return REPLACEMENT_CHARACTER;
    685       }
    686     }
    687 
    688     skip(byteCount);
    689 
    690     if (codePoint > 0x10ffff) {
    691       return REPLACEMENT_CHARACTER; // Reject code points larger than the Unicode maximum.
    692     }
    693 
    694     if (codePoint >= 0xd800 && codePoint <= 0xdfff) {
    695       return REPLACEMENT_CHARACTER; // Reject partial surrogates.
    696     }
    697 
    698     if (codePoint < min) {
    699       return REPLACEMENT_CHARACTER; // Reject overlong code points.
    700     }
    701 
    702     return codePoint;
    703   }
    704 
    705   @Override public byte[] readByteArray() {
    706     try {
    707       return readByteArray(size);
    708     } catch (EOFException e) {
    709       throw new AssertionError(e);
    710     }
    711   }
    712 
    713   @Override public byte[] readByteArray(long byteCount) throws EOFException {
    714     checkOffsetAndCount(size, 0, byteCount);
    715     if (byteCount > Integer.MAX_VALUE) {
    716       throw new IllegalArgumentException("byteCount > Integer.MAX_VALUE: " + byteCount);
    717     }
    718 
    719     byte[] result = new byte[(int) byteCount];
    720     readFully(result);
    721     return result;
    722   }
    723 
    724   @Override public int read(byte[] sink) {
    725     return read(sink, 0, sink.length);
    726   }
    727 
    728   @Override public void readFully(byte[] sink) throws EOFException {
    729     int offset = 0;
    730     while (offset < sink.length) {
    731       int read = read(sink, offset, sink.length - offset);
    732       if (read == -1) throw new EOFException();
    733       offset += read;
    734     }
    735   }
    736 
    737   @Override public int read(byte[] sink, int offset, int byteCount) {
    738     checkOffsetAndCount(sink.length, offset, byteCount);
    739 
    740     Segment s = head;
    741     if (s == null) return -1;
    742     int toCopy = Math.min(byteCount, s.limit - s.pos);
    743     System.arraycopy(s.data, s.pos, sink, offset, toCopy);
    744 
    745     s.pos += toCopy;
    746     size -= toCopy;
    747 
    748     if (s.pos == s.limit) {
    749       head = s.pop();
    750       SegmentPool.recycle(s);
    751     }
    752 
    753     return toCopy;
    754   }
    755 
    756   /**
    757    * Discards all bytes in this buffer. Calling this method when you're done
    758    * with a buffer will return its segments to the pool.
    759    */
    760   public void clear() {
    761     try {
    762       skip(size);
    763     } catch (EOFException e) {
    764       throw new AssertionError(e);
    765     }
    766   }
    767 
    768   /** Discards {@code byteCount} bytes from the head of this buffer. */
    769   @Override public void skip(long byteCount) throws EOFException {
    770     while (byteCount > 0) {
    771       if (head == null) throw new EOFException();
    772 
    773       int toSkip = (int) Math.min(byteCount, head.limit - head.pos);
    774       size -= toSkip;
    775       byteCount -= toSkip;
    776       head.pos += toSkip;
    777 
    778       if (head.pos == head.limit) {
    779         Segment toRecycle = head;
    780         head = toRecycle.pop();
    781         SegmentPool.recycle(toRecycle);
    782       }
    783     }
    784   }
    785 
    786   @Override public Buffer write(ByteString byteString) {
    787     if (byteString == null) throw new IllegalArgumentException("byteString == null");
    788     byteString.write(this);
    789     return this;
    790   }
    791 
    792   @Override public Buffer writeUtf8(String string) {
    793     return writeUtf8(string, 0, string.length());
    794   }
    795 
    796   @Override public Buffer writeUtf8(String string, int beginIndex, int endIndex) {
    797     if (string == null) throw new IllegalArgumentException("string == null");
    798     if (beginIndex < 0) throw new IllegalAccessError("beginIndex < 0: " + beginIndex);
    799     if (endIndex < beginIndex) {
    800       throw new IllegalArgumentException("endIndex < beginIndex: " + endIndex + " < " + beginIndex);
    801     }
    802     if (endIndex > string.length()) {
    803       throw new IllegalArgumentException(
    804           "endIndex > string.length: " + endIndex + " > " + string.length());
    805     }
    806 
    807     // Transcode a UTF-16 Java String to UTF-8 bytes.
    808     for (int i = beginIndex; i < endIndex;) {
    809       int c = string.charAt(i);
    810 
    811       if (c < 0x80) {
    812         Segment tail = writableSegment(1);
    813         byte[] data = tail.data;
    814         int segmentOffset = tail.limit - i;
    815         int runLimit = Math.min(endIndex, Segment.SIZE - segmentOffset);
    816 
    817         // Emit a 7-bit character with 1 byte.
    818         data[segmentOffset + i++] = (byte) c; // 0xxxxxxx
    819 
    820         // Fast-path contiguous runs of ASCII characters. This is ugly, but yields a ~4x performance
    821         // improvement over independent calls to writeByte().
    822         while (i < runLimit) {
    823           c = string.charAt(i);
    824           if (c >= 0x80) break;
    825           data[segmentOffset + i++] = (byte) c; // 0xxxxxxx
    826         }
    827 
    828         int runSize = i + segmentOffset - tail.limit; // Equivalent to i - (previous i).
    829         tail.limit += runSize;
    830         size += runSize;
    831 
    832       } else if (c < 0x800) {
    833         // Emit a 11-bit character with 2 bytes.
    834         writeByte(c >>  6        | 0xc0); // 110xxxxx
    835         writeByte(c       & 0x3f | 0x80); // 10xxxxxx
    836         i++;
    837 
    838       } else if (c < 0xd800 || c > 0xdfff) {
    839         // Emit a 16-bit character with 3 bytes.
    840         writeByte(c >> 12        | 0xe0); // 1110xxxx
    841         writeByte(c >>  6 & 0x3f | 0x80); // 10xxxxxx
    842         writeByte(c       & 0x3f | 0x80); // 10xxxxxx
    843         i++;
    844 
    845       } else {
    846         // c is a surrogate. Make sure it is a high surrogate & that its successor is a low
    847         // surrogate. If not, the UTF-16 is invalid, in which case we emit a replacement character.
    848         int low = i + 1 < endIndex ? string.charAt(i + 1) : 0;
    849         if (c > 0xdbff || low < 0xdc00 || low > 0xdfff) {
    850           writeByte('?');
    851           i++;
    852           continue;
    853         }
    854 
    855         // UTF-16 high surrogate: 110110xxxxxxxxxx (10 bits)
    856         // UTF-16 low surrogate:  110111yyyyyyyyyy (10 bits)
    857         // Unicode code point:    00010000000000000000 + xxxxxxxxxxyyyyyyyyyy (21 bits)
    858         int codePoint = 0x010000 + ((c & ~0xd800) << 10 | low & ~0xdc00);
    859 
    860         // Emit a 21-bit character with 4 bytes.
    861         writeByte(codePoint >> 18        | 0xf0); // 11110xxx
    862         writeByte(codePoint >> 12 & 0x3f | 0x80); // 10xxxxxx
    863         writeByte(codePoint >>  6 & 0x3f | 0x80); // 10xxyyyy
    864         writeByte(codePoint       & 0x3f | 0x80); // 10yyyyyy
    865         i += 2;
    866       }
    867     }
    868 
    869     return this;
    870   }
    871 
    872   @Override public Buffer writeUtf8CodePoint(int codePoint) {
    873     if (codePoint < 0x80) {
    874       // Emit a 7-bit code point with 1 byte.
    875       writeByte(codePoint);
    876 
    877     } else if (codePoint < 0x800) {
    878       // Emit a 11-bit code point with 2 bytes.
    879       writeByte(codePoint >>  6        | 0xc0); // 110xxxxx
    880       writeByte(codePoint       & 0x3f | 0x80); // 10xxxxxx
    881 
    882     } else if (codePoint < 0x10000) {
    883       if (codePoint >= 0xd800 && codePoint <= 0xdfff) {
    884         throw new IllegalArgumentException(
    885             "Unexpected code point: " + Integer.toHexString(codePoint));
    886       }
    887 
    888       // Emit a 16-bit code point with 3 bytes.
    889       writeByte(codePoint >> 12        | 0xe0); // 1110xxxx
    890       writeByte(codePoint >>  6 & 0x3f | 0x80); // 10xxxxxx
    891       writeByte(codePoint       & 0x3f | 0x80); // 10xxxxxx
    892 
    893     } else if (codePoint <= 0x10ffff) {
    894       // Emit a 21-bit code point with 4 bytes.
    895       writeByte(codePoint >> 18        | 0xf0); // 11110xxx
    896       writeByte(codePoint >> 12 & 0x3f | 0x80); // 10xxxxxx
    897       writeByte(codePoint >>  6 & 0x3f | 0x80); // 10xxxxxx
    898       writeByte(codePoint       & 0x3f | 0x80); // 10xxxxxx
    899 
    900     } else {
    901       throw new IllegalArgumentException(
    902           "Unexpected code point: " + Integer.toHexString(codePoint));
    903     }
    904 
    905     return this;
    906   }
    907 
    908   @Override public Buffer writeString(String string, Charset charset) {
    909     return writeString(string, 0, string.length(), charset);
    910   }
    911 
    912   @Override
    913   public Buffer writeString(String string, int beginIndex, int endIndex, Charset charset) {
    914     if (string == null) throw new IllegalArgumentException("string == null");
    915     if (beginIndex < 0) throw new IllegalAccessError("beginIndex < 0: " + beginIndex);
    916     if (endIndex < beginIndex) {
    917       throw new IllegalArgumentException("endIndex < beginIndex: " + endIndex + " < " + beginIndex);
    918     }
    919     if (endIndex > string.length()) {
    920       throw new IllegalArgumentException(
    921           "endIndex > string.length: " + endIndex + " > " + string.length());
    922     }
    923     if (charset == null) throw new IllegalArgumentException("charset == null");
    924     if (charset.equals(Util.UTF_8)) return writeUtf8(string);
    925     byte[] data = string.substring(beginIndex, endIndex).getBytes(charset);
    926     return write(data, 0, data.length);
    927   }
    928 
    929   @Override public Buffer write(byte[] source) {
    930     if (source == null) throw new IllegalArgumentException("source == null");
    931     return write(source, 0, source.length);
    932   }
    933 
    934   @Override public Buffer write(byte[] source, int offset, int byteCount) {
    935     if (source == null) throw new IllegalArgumentException("source == null");
    936     checkOffsetAndCount(source.length, offset, byteCount);
    937 
    938     int limit = offset + byteCount;
    939     while (offset < limit) {
    940       Segment tail = writableSegment(1);
    941 
    942       int toCopy = Math.min(limit - offset, Segment.SIZE - tail.limit);
    943       System.arraycopy(source, offset, tail.data, tail.limit, toCopy);
    944 
    945       offset += toCopy;
    946       tail.limit += toCopy;
    947     }
    948 
    949     size += byteCount;
    950     return this;
    951   }
    952 
    953   @Override public long writeAll(Source source) throws IOException {
    954     if (source == null) throw new IllegalArgumentException("source == null");
    955     long totalBytesRead = 0;
    956     for (long readCount; (readCount = source.read(this, Segment.SIZE)) != -1; ) {
    957       totalBytesRead += readCount;
    958     }
    959     return totalBytesRead;
    960   }
    961 
    962   @Override public BufferedSink write(Source source, long byteCount) throws IOException {
    963     while (byteCount > 0) {
    964       long read = source.read(this, byteCount);
    965       if (read == -1) throw new EOFException();
    966       byteCount -= read;
    967     }
    968     return this;
    969   }
    970 
    971   @Override public Buffer writeByte(int b) {
    972     Segment tail = writableSegment(1);
    973     tail.data[tail.limit++] = (byte) b;
    974     size += 1;
    975     return this;
    976   }
    977 
    978   @Override public Buffer writeShort(int s) {
    979     Segment tail = writableSegment(2);
    980     byte[] data = tail.data;
    981     int limit = tail.limit;
    982     data[limit++] = (byte) ((s >>> 8) & 0xff);
    983     data[limit++] = (byte)  (s        & 0xff);
    984     tail.limit = limit;
    985     size += 2;
    986     return this;
    987   }
    988 
    989   @Override public Buffer writeShortLe(int s) {
    990     return writeShort(Util.reverseBytesShort((short) s));
    991   }
    992 
    993   @Override public Buffer writeInt(int i) {
    994     Segment tail = writableSegment(4);
    995     byte[] data = tail.data;
    996     int limit = tail.limit;
    997     data[limit++] = (byte) ((i >>> 24) & 0xff);
    998     data[limit++] = (byte) ((i >>> 16) & 0xff);
    999     data[limit++] = (byte) ((i >>>  8) & 0xff);
   1000     data[limit++] = (byte)  (i         & 0xff);
   1001     tail.limit = limit;
   1002     size += 4;
   1003     return this;
   1004   }
   1005 
   1006   @Override public Buffer writeIntLe(int i) {
   1007     return writeInt(Util.reverseBytesInt(i));
   1008   }
   1009 
   1010   @Override public Buffer writeLong(long v) {
   1011     Segment tail = writableSegment(8);
   1012     byte[] data = tail.data;
   1013     int limit = tail.limit;
   1014     data[limit++] = (byte) ((v >>> 56L) & 0xff);
   1015     data[limit++] = (byte) ((v >>> 48L) & 0xff);
   1016     data[limit++] = (byte) ((v >>> 40L) & 0xff);
   1017     data[limit++] = (byte) ((v >>> 32L) & 0xff);
   1018     data[limit++] = (byte) ((v >>> 24L) & 0xff);
   1019     data[limit++] = (byte) ((v >>> 16L) & 0xff);
   1020     data[limit++] = (byte) ((v >>>  8L) & 0xff);
   1021     data[limit++] = (byte)  (v          & 0xff);
   1022     tail.limit = limit;
   1023     size += 8;
   1024     return this;
   1025   }
   1026 
   1027   @Override public Buffer writeLongLe(long v) {
   1028     return writeLong(reverseBytesLong(v));
   1029   }
   1030 
   1031   @Override public Buffer writeDecimalLong(long v) {
   1032     if (v == 0) {
   1033       // Both a shortcut and required since the following code can't handle zero.
   1034       return writeByte('0');
   1035     }
   1036 
   1037     boolean negative = false;
   1038     if (v < 0) {
   1039       v = -v;
   1040       if (v < 0) { // Only true for Long.MIN_VALUE.
   1041         return writeUtf8("-9223372036854775808");
   1042       }
   1043       negative = true;
   1044     }
   1045 
   1046     // Binary search for character width which favors matching lower numbers.
   1047     int width = //
   1048           v < 100000000L
   1049         ? v < 10000L
   1050         ? v < 100L
   1051         ? v < 10L ? 1 : 2
   1052         : v < 1000L ? 3 : 4
   1053         : v < 1000000L
   1054         ? v < 100000L ? 5 : 6
   1055         : v < 10000000L ? 7 : 8
   1056         : v < 1000000000000L
   1057         ? v < 10000000000L
   1058         ? v < 1000000000L ? 9 : 10
   1059         : v < 100000000000L ? 11 : 12
   1060         : v < 1000000000000000L
   1061         ? v < 10000000000000L ? 13
   1062         : v < 100000000000000L ? 14 : 15
   1063         : v < 100000000000000000L
   1064         ? v < 10000000000000000L ? 16 : 17
   1065         : v < 1000000000000000000L ? 18 : 19;
   1066     if (negative) {
   1067       ++width;
   1068     }
   1069 
   1070     Segment tail = writableSegment(width);
   1071     byte[] data = tail.data;
   1072     int pos = tail.limit + width; // We write backwards from right to left.
   1073     while (v != 0) {
   1074       int digit = (int) (v % 10);
   1075       data[--pos] = DIGITS[digit];
   1076       v /= 10;
   1077     }
   1078     if (negative) {
   1079       data[--pos] = '-';
   1080     }
   1081 
   1082     tail.limit += width;
   1083     this.size += width;
   1084     return this;
   1085   }
   1086 
   1087   @Override public Buffer writeHexadecimalUnsignedLong(long v) {
   1088     if (v == 0) {
   1089       // Both a shortcut and required since the following code can't handle zero.
   1090       return writeByte('0');
   1091     }
   1092 
   1093     int width = Long.numberOfTrailingZeros(Long.highestOneBit(v)) / 4 + 1;
   1094 
   1095     Segment tail = writableSegment(width);
   1096     byte[] data = tail.data;
   1097     for (int pos = tail.limit + width - 1, start = tail.limit; pos >= start; pos--) {
   1098       data[pos] = DIGITS[(int) (v & 0xF)];
   1099       v >>>= 4;
   1100     }
   1101     tail.limit += width;
   1102     size += width;
   1103     return this;
   1104   }
   1105 
   1106   /**
   1107    * Returns a tail segment that we can write at least {@code minimumCapacity}
   1108    * bytes to, creating it if necessary.
   1109    */
   1110   Segment writableSegment(int minimumCapacity) {
   1111     if (minimumCapacity < 1 || minimumCapacity > Segment.SIZE) throw new IllegalArgumentException();
   1112 
   1113     if (head == null) {
   1114       head = SegmentPool.take(); // Acquire a first segment.
   1115       return head.next = head.prev = head;
   1116     }
   1117 
   1118     Segment tail = head.prev;
   1119     if (tail.limit + minimumCapacity > Segment.SIZE || !tail.owner) {
   1120       tail = tail.push(SegmentPool.take()); // Append a new empty segment to fill up.
   1121     }
   1122     return tail;
   1123   }
   1124 
   1125   @Override public void write(Buffer source, long byteCount) {
   1126     // Move bytes from the head of the source buffer to the tail of this buffer
   1127     // while balancing two conflicting goals: don't waste CPU and don't waste
   1128     // memory.
   1129     //
   1130     //
   1131     // Don't waste CPU (ie. don't copy data around).
   1132     //
   1133     // Copying large amounts of data is expensive. Instead, we prefer to
   1134     // reassign entire segments from one buffer to the other.
   1135     //
   1136     //
   1137     // Don't waste memory.
   1138     //
   1139     // As an invariant, adjacent pairs of segments in a buffer should be at
   1140     // least 50% full, except for the head segment and the tail segment.
   1141     //
   1142     // The head segment cannot maintain the invariant because the application is
   1143     // consuming bytes from this segment, decreasing its level.
   1144     //
   1145     // The tail segment cannot maintain the invariant because the application is
   1146     // producing bytes, which may require new nearly-empty tail segments to be
   1147     // appended.
   1148     //
   1149     //
   1150     // Moving segments between buffers
   1151     //
   1152     // When writing one buffer to another, we prefer to reassign entire segments
   1153     // over copying bytes into their most compact form. Suppose we have a buffer
   1154     // with these segment levels [91%, 61%]. If we append a buffer with a
   1155     // single [72%] segment, that yields [91%, 61%, 72%]. No bytes are copied.
   1156     //
   1157     // Or suppose we have a buffer with these segment levels: [100%, 2%], and we
   1158     // want to append it to a buffer with these segment levels [99%, 3%]. This
   1159     // operation will yield the following segments: [100%, 2%, 99%, 3%]. That
   1160     // is, we do not spend time copying bytes around to achieve more efficient
   1161     // memory use like [100%, 100%, 4%].
   1162     //
   1163     // When combining buffers, we will compact adjacent buffers when their
   1164     // combined level doesn't exceed 100%. For example, when we start with
   1165     // [100%, 40%] and append [30%, 80%], the result is [100%, 70%, 80%].
   1166     //
   1167     //
   1168     // Splitting segments
   1169     //
   1170     // Occasionally we write only part of a source buffer to a sink buffer. For
   1171     // example, given a sink [51%, 91%], we may want to write the first 30% of
   1172     // a source [92%, 82%] to it. To simplify, we first transform the source to
   1173     // an equivalent buffer [30%, 62%, 82%] and then move the head segment,
   1174     // yielding sink [51%, 91%, 30%] and source [62%, 82%].
   1175 
   1176     if (source == null) throw new IllegalArgumentException("source == null");
   1177     if (source == this) throw new IllegalArgumentException("source == this");
   1178     checkOffsetAndCount(source.size, 0, byteCount);
   1179 
   1180     while (byteCount > 0) {
   1181       // Is a prefix of the source's head segment all that we need to move?
   1182       if (byteCount < (source.head.limit - source.head.pos)) {
   1183         Segment tail = head != null ? head.prev : null;
   1184         if (tail != null && tail.owner
   1185             && (byteCount + tail.limit - (tail.shared ? 0 : tail.pos) <= Segment.SIZE)) {
   1186           // Our existing segments are sufficient. Move bytes from source's head to our tail.
   1187           source.head.writeTo(tail, (int) byteCount);
   1188           source.size -= byteCount;
   1189           size += byteCount;
   1190           return;
   1191         } else {
   1192           // We're going to need another segment. Split the source's head
   1193           // segment in two, then move the first of those two to this buffer.
   1194           source.head = source.head.split((int) byteCount);
   1195         }
   1196       }
   1197 
   1198       // Remove the source's head segment and append it to our tail.
   1199       Segment segmentToMove = source.head;
   1200       long movedByteCount = segmentToMove.limit - segmentToMove.pos;
   1201       source.head = segmentToMove.pop();
   1202       if (head == null) {
   1203         head = segmentToMove;
   1204         head.next = head.prev = head;
   1205       } else {
   1206         Segment tail = head.prev;
   1207         tail = tail.push(segmentToMove);
   1208         tail.compact();
   1209       }
   1210       source.size -= movedByteCount;
   1211       size += movedByteCount;
   1212       byteCount -= movedByteCount;
   1213     }
   1214   }
   1215 
   1216   @Override public long read(Buffer sink, long byteCount) {
   1217     if (sink == null) throw new IllegalArgumentException("sink == null");
   1218     if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
   1219     if (size == 0) return -1L;
   1220     if (byteCount > size) byteCount = size;
   1221     sink.write(this, byteCount);
   1222     return byteCount;
   1223   }
   1224 
   1225   @Override public long indexOf(byte b) {
   1226     return indexOf(b, 0);
   1227   }
   1228 
   1229   /**
   1230    * Returns the index of {@code b} in this at or beyond {@code fromIndex}, or
   1231    * -1 if this buffer does not contain {@code b} in that range.
   1232    */
   1233   @Override public long indexOf(byte b, long fromIndex) {
   1234     if (fromIndex < 0) throw new IllegalArgumentException("fromIndex < 0");
   1235 
   1236     Segment s = head;
   1237     if (s == null) return -1L;
   1238     long offset = 0L;
   1239     do {
   1240       int segmentByteCount = s.limit - s.pos;
   1241       if (fromIndex >= segmentByteCount) {
   1242         fromIndex -= segmentByteCount;
   1243       } else {
   1244         byte[] data = s.data;
   1245         for (int pos = (int) (s.pos + fromIndex), limit = s.limit; pos < limit; pos++) {
   1246           if (data[pos] == b) return offset + pos - s.pos;
   1247         }
   1248         fromIndex = 0;
   1249       }
   1250       offset += segmentByteCount;
   1251       s = s.next;
   1252     } while (s != head);
   1253     return -1L;
   1254   }
   1255 
   1256   @Override public long indexOf(ByteString bytes) throws IOException {
   1257     return indexOf(bytes, 0);
   1258   }
   1259 
   1260   @Override public long indexOf(ByteString bytes, long fromIndex) throws IOException {
   1261     if (bytes.size() == 0) throw new IllegalArgumentException("bytes is empty");
   1262     while (true) {
   1263       fromIndex = indexOf(bytes.getByte(0), fromIndex);
   1264       if (fromIndex == -1) {
   1265         return -1;
   1266       }
   1267       if (rangeEquals(fromIndex, bytes)) {
   1268         return fromIndex;
   1269       }
   1270       fromIndex++;
   1271     }
   1272   }
   1273 
   1274   @Override public long indexOfElement(ByteString targetBytes) {
   1275     return indexOfElement(targetBytes, 0);
   1276   }
   1277 
   1278   @Override public long indexOfElement(ByteString targetBytes, long fromIndex) {
   1279     if (fromIndex < 0) throw new IllegalArgumentException("fromIndex < 0");
   1280 
   1281     Segment s = head;
   1282     if (s == null) return -1L;
   1283     long offset = 0L;
   1284     byte[] toFind = targetBytes.toByteArray();
   1285     do {
   1286       int segmentByteCount = s.limit - s.pos;
   1287       if (fromIndex >= segmentByteCount) {
   1288         fromIndex -= segmentByteCount;
   1289       } else {
   1290         byte[] data = s.data;
   1291         for (long pos = s.pos + fromIndex, limit = s.limit; pos < limit; pos++) {
   1292           byte b = data[(int) pos];
   1293           for (byte targetByte : toFind) {
   1294             if (b == targetByte) return offset + pos - s.pos;
   1295           }
   1296         }
   1297         fromIndex = 0;
   1298       }
   1299       offset += segmentByteCount;
   1300       s = s.next;
   1301     } while (s != head);
   1302     return -1L;
   1303   }
   1304 
   1305   boolean rangeEquals(long offset, ByteString bytes) {
   1306     int byteCount = bytes.size();
   1307     if (size - offset < byteCount) {
   1308       return false;
   1309     }
   1310     for (int i = 0; i < byteCount; i++) {
   1311       if (getByte(offset + i) != bytes.getByte(i)) {
   1312         return false;
   1313       }
   1314     }
   1315     return true;
   1316   }
   1317 
   1318   @Override public void flush() {
   1319   }
   1320 
   1321   @Override public void close() {
   1322   }
   1323 
   1324   @Override public Timeout timeout() {
   1325     return Timeout.NONE;
   1326   }
   1327 
   1328   /** For testing. This returns the sizes of the segments in this buffer. */
   1329   List<Integer> segmentSizes() {
   1330     if (head == null) return Collections.emptyList();
   1331     List<Integer> result = new ArrayList<>();
   1332     result.add(head.limit - head.pos);
   1333     for (Segment s = head.next; s != head; s = s.next) {
   1334       result.add(s.limit - s.pos);
   1335     }
   1336     return result;
   1337   }
   1338 
   1339   @Override public boolean equals(Object o) {
   1340     if (this == o) return true;
   1341     if (!(o instanceof Buffer)) return false;
   1342     Buffer that = (Buffer) o;
   1343     if (size != that.size) return false;
   1344     if (size == 0) return true; // Both buffers are empty.
   1345 
   1346     Segment sa = this.head;
   1347     Segment sb = that.head;
   1348     int posA = sa.pos;
   1349     int posB = sb.pos;
   1350 
   1351     for (long pos = 0, count; pos < size; pos += count) {
   1352       count = Math.min(sa.limit - posA, sb.limit - posB);
   1353 
   1354       for (int i = 0; i < count; i++) {
   1355         if (sa.data[posA++] != sb.data[posB++]) return false;
   1356       }
   1357 
   1358       if (posA == sa.limit) {
   1359         sa = sa.next;
   1360         posA = sa.pos;
   1361       }
   1362 
   1363       if (posB == sb.limit) {
   1364         sb = sb.next;
   1365         posB = sb.pos;
   1366       }
   1367     }
   1368 
   1369     return true;
   1370   }
   1371 
   1372   @Override public int hashCode() {
   1373     Segment s = head;
   1374     if (s == null) return 0;
   1375     int result = 1;
   1376     do {
   1377       for (int pos = s.pos, limit = s.limit; pos < limit; pos++) {
   1378         result = 31 * result + s.data[pos];
   1379       }
   1380       s = s.next;
   1381     } while (s != head);
   1382     return result;
   1383   }
   1384 
   1385   @Override public String toString() {
   1386     if (size == 0) {
   1387       return "Buffer[size=0]";
   1388     }
   1389 
   1390     if (size <= 16) {
   1391       ByteString data = clone().readByteString();
   1392       return String.format("Buffer[size=%s data=%s]", size, data.hex());
   1393     }
   1394 
   1395     try {
   1396       MessageDigest md5 = MessageDigest.getInstance("MD5");
   1397       md5.update(head.data, head.pos, head.limit - head.pos);
   1398       for (Segment s = head.next; s != head; s = s.next) {
   1399         md5.update(s.data, s.pos, s.limit - s.pos);
   1400       }
   1401       return String.format("Buffer[size=%s md5=%s]",
   1402           size, ByteString.of(md5.digest()).hex());
   1403     } catch (NoSuchAlgorithmException e) {
   1404       throw new AssertionError();
   1405     }
   1406   }
   1407 
   1408   /** Returns a deep copy of this buffer. */
   1409   @Override public Buffer clone() {
   1410     Buffer result = new Buffer();
   1411     if (size == 0) return result;
   1412 
   1413     result.head = new Segment(head);
   1414     result.head.next = result.head.prev = result.head;
   1415     for (Segment s = head.next; s != head; s = s.next) {
   1416       result.head.prev.push(new Segment(s));
   1417     }
   1418     result.size = size;
   1419     return result;
   1420   }
   1421 
   1422   /** Returns an immutable copy of this buffer as a byte string. */
   1423   public ByteString snapshot() {
   1424     if (size > Integer.MAX_VALUE) {
   1425       throw new IllegalArgumentException("size > Integer.MAX_VALUE: " + size);
   1426     }
   1427     return snapshot((int) size);
   1428   }
   1429 
   1430   /**
   1431    * Returns an immutable copy of the first {@code byteCount} bytes of this buffer as a byte string.
   1432    */
   1433   public ByteString snapshot(int byteCount) {
   1434     if (byteCount == 0) return ByteString.EMPTY;
   1435     return new SegmentedByteString(this, byteCount);
   1436   }
   1437 }
   1438