1 /* 2 * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net.www; 27 28 import java.net.URL; 29 import java.util.*; 30 import java.io.*; 31 import sun.net.ProgressSource; 32 33 34 public class MeteredStream extends FilterInputStream { 35 36 // Instance variables. 37 /* if expected != -1, after we've read >= expected, we're "closed" and return -1 38 * from subsequest read() 's 39 */ 40 protected boolean closed = false; 41 protected long expected; 42 protected long count = 0; 43 protected long markedCount = 0; 44 protected int markLimit = -1; 45 protected ProgressSource pi; 46 MeteredStream(InputStream is, ProgressSource pi, long expected)47 public MeteredStream(InputStream is, ProgressSource pi, long expected) 48 { 49 super(is); 50 51 this.pi = pi; 52 this.expected = expected; 53 54 if (pi != null) { 55 pi.updateProgress(0, expected); 56 } 57 } 58 justRead(long n)59 private final void justRead(long n) throws IOException { 60 if (n == -1) { 61 62 /* 63 * don't close automatically when mark is set and is valid; 64 * cannot reset() after close() 65 */ 66 if (!isMarked()) { 67 close(); 68 } 69 return; 70 } 71 72 count += n; 73 74 /** 75 * If read beyond the markLimit, invalidate the mark 76 */ 77 if (count - markedCount > markLimit) { 78 markLimit = -1; 79 } 80 81 if (pi != null) 82 pi.updateProgress(count, expected); 83 84 if (isMarked()) { 85 return; 86 } 87 88 // if expected length is known, we could determine if 89 // read overrun. 90 if (expected > 0) { 91 if (count >= expected) { 92 close(); 93 } 94 } 95 } 96 97 /** 98 * Returns true if the mark is valid, false otherwise 99 */ isMarked()100 private boolean isMarked() { 101 102 if (markLimit < 0) { 103 return false; 104 } 105 106 // mark is set, but is not valid anymore 107 if (count - markedCount > markLimit) { 108 return false; 109 } 110 111 // mark still holds 112 return true; 113 } 114 read()115 public synchronized int read() throws java.io.IOException { 116 if (closed) { 117 return -1; 118 } 119 int c = in.read(); 120 if (c != -1) { 121 justRead(1); 122 } else { 123 justRead(c); 124 } 125 return c; 126 } 127 read(byte b[], int off, int len)128 public synchronized int read(byte b[], int off, int len) 129 throws java.io.IOException { 130 if (closed) { 131 return -1; 132 } 133 int n = in.read(b, off, len); 134 justRead(n); 135 return n; 136 } 137 skip(long n)138 public synchronized long skip(long n) throws IOException { 139 140 // REMIND: what does skip do on EOF???? 141 if (closed) { 142 return 0; 143 } 144 145 // Android-changed: Remove support for Android-removed class ChunkedInputSTream 146 // if (in instanceof ChunkedInputStream) { 147 // n = in.skip(n); 148 // } 149 // else { 150 // just skip min(n, num_bytes_left) 151 long min = (n > expected - count) ? expected - count: n; 152 n = in.skip(min); 153 // } 154 justRead(n); 155 return n; 156 } 157 close()158 public void close() throws IOException { 159 if (closed) { 160 return; 161 } 162 if (pi != null) 163 pi.finishTracking(); 164 165 closed = true; 166 in.close(); 167 } 168 available()169 public synchronized int available() throws IOException { 170 return closed ? 0: in.available(); 171 } 172 mark(int readLimit)173 public synchronized void mark(int readLimit) { 174 if (closed) { 175 return; 176 } 177 super.mark(readLimit); 178 179 /* 180 * mark the count to restore upon reset 181 */ 182 markedCount = count; 183 markLimit = readLimit; 184 } 185 reset()186 public synchronized void reset() throws IOException { 187 if (closed) { 188 return; 189 } 190 191 if (!isMarked()) { 192 throw new IOException ("Resetting to an invalid mark"); 193 } 194 195 count = markedCount; 196 super.reset(); 197 } 198 markSupported()199 public boolean markSupported() { 200 if (closed) { 201 return false; 202 } 203 return super.markSupported(); 204 } 205 finalize()206 protected void finalize() throws Throwable { 207 try { 208 close(); 209 if (pi != null) 210 pi.close(); 211 } 212 finally { 213 // Call super class 214 super.finalize(); 215 } 216 } 217 } 218