mobile/android/thirdparty/com/squareup/picasso/MarkableInputStream.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 * Copyright (C) 2013 Square, Inc.
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16 package com.squareup.picasso;
michael@0 17
michael@0 18 import java.io.BufferedInputStream;
michael@0 19 import java.io.IOException;
michael@0 20 import java.io.InputStream;
michael@0 21
michael@0 22 /**
michael@0 23 * An input stream wrapper that supports unlimited independent cursors for
michael@0 24 * marking and resetting. Each cursor is a token, and it's the caller's
michael@0 25 * responsibility to keep track of these.
michael@0 26 */
michael@0 27 final class MarkableInputStream extends InputStream {
michael@0 28 private final InputStream in;
michael@0 29
michael@0 30 private long offset;
michael@0 31 private long reset;
michael@0 32 private long limit;
michael@0 33
michael@0 34 private long defaultMark = -1;
michael@0 35
michael@0 36 public MarkableInputStream(InputStream in) {
michael@0 37 if (!in.markSupported()) {
michael@0 38 in = new BufferedInputStream(in);
michael@0 39 }
michael@0 40 this.in = in;
michael@0 41 }
michael@0 42
michael@0 43 /** Marks this place in the stream so we can reset back to it later. */
michael@0 44 @Override public void mark(int readLimit) {
michael@0 45 defaultMark = savePosition(readLimit);
michael@0 46 }
michael@0 47
michael@0 48 /**
michael@0 49 * Returns an opaque token representing the current position in the stream.
michael@0 50 * Call {@link #reset(long)} to return to this position in the stream later.
michael@0 51 * It is an error to call {@link #reset(long)} after consuming more than
michael@0 52 * {@code readLimit} bytes from this stream.
michael@0 53 */
michael@0 54 public long savePosition(int readLimit) {
michael@0 55 long offsetLimit = offset + readLimit;
michael@0 56 if (limit < offsetLimit) {
michael@0 57 setLimit(offsetLimit);
michael@0 58 }
michael@0 59 return offset;
michael@0 60 }
michael@0 61
michael@0 62 /**
michael@0 63 * Makes sure that the underlying stream can backtrack the full range from
michael@0 64 * {@code reset} thru {@code limit}. Since we can't call {@code mark()}
michael@0 65 * without also adjusting the reset-to-position on the underlying stream this
michael@0 66 * method resets first and then marks the union of the two byte ranges. On
michael@0 67 * buffered streams this additional cursor motion shouldn't result in any
michael@0 68 * additional I/O.
michael@0 69 */
michael@0 70 private void setLimit(long limit) {
michael@0 71 try {
michael@0 72 if (reset < offset && offset <= this.limit) {
michael@0 73 in.reset();
michael@0 74 in.mark((int) (limit - reset));
michael@0 75 skip(reset, offset);
michael@0 76 } else {
michael@0 77 reset = offset;
michael@0 78 in.mark((int) (limit - offset));
michael@0 79 }
michael@0 80 this.limit = limit;
michael@0 81 } catch (IOException e) {
michael@0 82 throw new IllegalStateException("Unable to mark: " + e);
michael@0 83 }
michael@0 84 }
michael@0 85
michael@0 86 /** Resets the stream to the most recent {@link #mark mark}. */
michael@0 87 @Override public void reset() throws IOException {
michael@0 88 reset(defaultMark);
michael@0 89 }
michael@0 90
michael@0 91 /** Resets the stream to the position recorded by {@code token}. */
michael@0 92 public void reset(long token) throws IOException {
michael@0 93 if (offset > limit || token < reset) {
michael@0 94 throw new IOException("Cannot reset");
michael@0 95 }
michael@0 96 in.reset();
michael@0 97 skip(reset, token);
michael@0 98 offset = token;
michael@0 99 }
michael@0 100
michael@0 101 /** Skips {@code target - current} bytes and returns. */
michael@0 102 private void skip(long current, long target) throws IOException {
michael@0 103 while (current < target) {
michael@0 104 long skipped = in.skip(target - current);
michael@0 105 if (skipped == 0) {
michael@0 106 if (read() == -1) {
michael@0 107 break; // EOF
michael@0 108 } else {
michael@0 109 skipped = 1;
michael@0 110 }
michael@0 111 }
michael@0 112 current += skipped;
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 @Override public int read() throws IOException {
michael@0 117 int result = in.read();
michael@0 118 if (result != -1) {
michael@0 119 offset++;
michael@0 120 }
michael@0 121 return result;
michael@0 122 }
michael@0 123
michael@0 124 @Override public int read(byte[] buffer) throws IOException {
michael@0 125 int count = in.read(buffer);
michael@0 126 if (count != -1) {
michael@0 127 offset += count;
michael@0 128 }
michael@0 129 return count;
michael@0 130 }
michael@0 131
michael@0 132 @Override public int read(byte[] buffer, int offset, int length) throws IOException {
michael@0 133 int count = in.read(buffer, offset, length);
michael@0 134 if (count != -1) {
michael@0 135 this.offset += count;
michael@0 136 }
michael@0 137 return count;
michael@0 138 }
michael@0 139
michael@0 140 @Override public long skip(long byteCount) throws IOException {
michael@0 141 long skipped = in.skip(byteCount);
michael@0 142 offset += skipped;
michael@0 143 return skipped;
michael@0 144 }
michael@0 145
michael@0 146 @Override public int available() throws IOException {
michael@0 147 return in.available();
michael@0 148 }
michael@0 149
michael@0 150 @Override public void close() throws IOException {
michael@0 151 in.close();
michael@0 152 }
michael@0 153
michael@0 154 @Override public boolean markSupported() {
michael@0 155 return in.markSupported();
michael@0 156 }
michael@0 157 }

mercurial