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.IOException;
     19 import java.io.InputStream;
     20 import java.io.OutputStream;
     21 
     22 import static okio.Util.checkOffsetAndCount;
     23 
     24 public final class Okio {
     25   private Okio() {
     26   }
     27 
     28   public static BufferedSource buffer(Source source) {
     29     return new RealBufferedSource(source);
     30   }
     31 
     32   public static BufferedSink buffer(Sink sink) {
     33     return new RealBufferedSink(sink);
     34   }
     35 
     36   /** Copies bytes from {@code source} to {@code sink}. */
     37   public static void copy(OkBuffer source, long offset, long byteCount, OutputStream sink)
     38       throws IOException {
     39     checkOffsetAndCount(source.size, offset, byteCount);
     40 
     41     // Skip segments that we aren't copying from.
     42     Segment s = source.head;
     43     while (offset >= (s.limit - s.pos)) {
     44       offset -= (s.limit - s.pos);
     45       s = s.next;
     46     }
     47 
     48     // Copy from one segment at a time.
     49     while (byteCount > 0) {
     50       int pos = (int) (s.pos + offset);
     51       int toWrite = (int) Math.min(s.limit - pos, byteCount);
     52       sink.write(s.data, pos, toWrite);
     53       byteCount -= toWrite;
     54       offset = 0;
     55     }
     56   }
     57 
     58   /** Returns a sink that writes to {@code out}. */
     59   public static Sink sink(final OutputStream out) {
     60     return new Sink() {
     61       private Deadline deadline = Deadline.NONE;
     62 
     63       @Override public void write(OkBuffer source, long byteCount)
     64           throws IOException {
     65         checkOffsetAndCount(source.size, 0, byteCount);
     66         while (byteCount > 0) {
     67           deadline.throwIfReached();
     68           Segment head = source.head;
     69           int toCopy = (int) Math.min(byteCount, head.limit - head.pos);
     70           out.write(head.data, head.pos, toCopy);
     71 
     72           head.pos += toCopy;
     73           byteCount -= toCopy;
     74           source.size -= toCopy;
     75 
     76           if (head.pos == head.limit) {
     77             source.head = head.pop();
     78             SegmentPool.INSTANCE.recycle(head);
     79           }
     80         }
     81       }
     82 
     83       @Override public void flush() throws IOException {
     84         out.flush();
     85       }
     86 
     87       @Override public void close() throws IOException {
     88         out.close();
     89       }
     90 
     91       @Override public Sink deadline(Deadline deadline) {
     92         if (deadline == null) throw new IllegalArgumentException("deadline == null");
     93         this.deadline = deadline;
     94         return this;
     95       }
     96 
     97       @Override public String toString() {
     98         return "sink(" + out + ")";
     99       }
    100     };
    101   }
    102 
    103   /** Returns a source that reads from {@code in}. */
    104   public static Source source(final InputStream in) {
    105     return new Source() {
    106       private Deadline deadline = Deadline.NONE;
    107 
    108       @Override public long read(OkBuffer sink, long byteCount) throws IOException {
    109         if (byteCount < 0) throw new IllegalArgumentException("byteCount < 0: " + byteCount);
    110         deadline.throwIfReached();
    111         Segment tail = sink.writableSegment(1);
    112         int maxToCopy = (int) Math.min(byteCount, Segment.SIZE - tail.limit);
    113         int bytesRead = in.read(tail.data, tail.limit, maxToCopy);
    114         if (bytesRead == -1) return -1;
    115         tail.limit += bytesRead;
    116         sink.size += bytesRead;
    117         return bytesRead;
    118       }
    119 
    120       @Override public void close() throws IOException {
    121         in.close();
    122       }
    123 
    124       @Override public Source deadline(Deadline deadline) {
    125         if (deadline == null) throw new IllegalArgumentException("deadline == null");
    126         this.deadline = deadline;
    127         return this;
    128       }
    129 
    130       @Override public String toString() {
    131         return "source(" + in + ")";
    132       }
    133     };
    134   }
    135 }
    136