13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/*
23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2014 Square, Inc.
33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License");
53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License.
63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at
73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *      http://www.apache.org/licenses/LICENSE-2.0
93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software
113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS,
123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and
143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License.
153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */
163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage okio;
173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.IOException;
193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.OutputStream;
203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerfinal class RealBufferedSink implements BufferedSink {
223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public final OkBuffer buffer;
233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public final Sink sink;
243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private boolean closed;
253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public RealBufferedSink(Sink sink, OkBuffer buffer) {
273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (sink == null) throw new IllegalArgumentException("sink == null");
283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    this.buffer = buffer;
293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    this.sink = sink;
303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public RealBufferedSink(Sink sink) {
333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    this(sink, new OkBuffer());
343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public OkBuffer buffer() {
373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return buffer;
383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public void write(OkBuffer source, long byteCount)
413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      throws IOException {
42c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.write(source, byteCount);
443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    emitCompleteSegments();
453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink write(ByteString byteString) throws IOException {
48c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.write(byteString);
503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink writeUtf8(String string) throws IOException {
54c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.writeUtf8(string);
563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink write(byte[] source) throws IOException {
60c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.write(source);
623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink write(byte[] source, int offset, int byteCount) throws IOException {
66c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.write(source, offset, byteCount);
683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink writeByte(int b) throws IOException {
72c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.writeByte(b);
743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink writeShort(int s) throws IOException {
78c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.writeShort(s);
803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
83c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Override public BufferedSink writeShortLe(int s) throws IOException {
84c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
85c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    buffer.writeShortLe(s);
86c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    return emitCompleteSegments();
87c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
88c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink writeInt(int i) throws IOException {
90c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    buffer.writeInt(i);
923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return emitCompleteSegments();
933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
95c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Override public BufferedSink writeIntLe(int i) throws IOException {
96c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
97c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    buffer.writeIntLe(i);
98c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    return emitCompleteSegments();
99c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
100c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
101c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Override public BufferedSink writeLong(long v) throws IOException {
102c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
103c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    buffer.writeLong(v);
104c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    return emitCompleteSegments();
105c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
106c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
107c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Override public BufferedSink writeLongLe(long v) throws IOException {
108c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
109c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    buffer.writeLongLe(v);
110c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    return emitCompleteSegments();
111c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
112c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public BufferedSink emitCompleteSegments() throws IOException {
114c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    long byteCount = buffer.completeSegmentByteCount();
1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (byteCount > 0) sink.write(buffer, byteCount);
1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return this;
1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public OutputStream outputStream() {
1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return new OutputStream() {
1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      @Override public void write(int b) throws IOException {
123c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        if (closed) throw new IOException("closed");
1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        buffer.writeByte((byte) b);
1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        emitCompleteSegments();
1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      @Override public void write(byte[] data, int offset, int byteCount) throws IOException {
129c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        if (closed) throw new IOException("closed");
1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        buffer.write(data, offset, byteCount);
1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        emitCompleteSegments();
1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      @Override public void flush() throws IOException {
1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        // For backwards compatibility, a flush() on a closed stream is a no-op.
136c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        if (!closed) {
1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller          RealBufferedSink.this.flush();
1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        }
1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      @Override public void close() throws IOException {
1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        RealBufferedSink.this.close();
1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      @Override public String toString() {
1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        return RealBufferedSink.this + ".outputStream()";
1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    };
1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public void flush() throws IOException {
152c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    if (closed) throw new IllegalStateException("closed");
1533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (buffer.size > 0) {
1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      sink.write(buffer, buffer.size);
1553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    sink.flush();
1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public void close() throws IOException {
1603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (closed) return;
1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Emit buffered data to the underlying sink. If this fails, we still need
1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // to close the sink; otherwise we risk leaking resources.
1643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Throwable thrown = null;
1653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (buffer.size > 0) {
1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        sink.write(buffer, buffer.size);
1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    } catch (Throwable e) {
1703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      thrown = e;
1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      sink.close();
1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    } catch (Throwable e) {
1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (thrown == null) thrown = e;
1773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    closed = true;
1793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (thrown != null) Util.sneakyRethrow(thrown);
1813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public Sink deadline(Deadline deadline) {
1843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    sink.deadline(deadline);
1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return this;
1863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Override public String toString() {
1893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return "buffer(" + sink + ")";
1903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller}
192