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-removed: Removed support for Android-removed class ChunkedInputStream. 146 /* 147 if (in instanceof ChunkedInputStream) { 148 n = in.skip(n); 149 } 150 else { 151 */ 152 // just skip min(n, num_bytes_left) 153 long min = (n > expected - count) ? expected - count: n; 154 n = in.skip(min); 155 // } 156 justRead(n); 157 return n; 158 } 159 160 // Android-changed: Added synchronize to prevent concurrent finalization. 161 // Since other relevant methods also synchronize on the same object, this prevents 162 // finalization while those methods are running. close()163 public synchronized void close() throws IOException { 164 if (closed) { 165 return; 166 } 167 if (pi != null) 168 pi.finishTracking(); 169 170 closed = true; 171 in.close(); 172 } 173 available()174 public synchronized int available() throws IOException { 175 return closed ? 0: in.available(); 176 } 177 mark(int readLimit)178 public synchronized void mark(int readLimit) { 179 if (closed) { 180 return; 181 } 182 super.mark(readLimit); 183 184 /* 185 * mark the count to restore upon reset 186 */ 187 markedCount = count; 188 markLimit = readLimit; 189 } 190 reset()191 public synchronized void reset() throws IOException { 192 if (closed) { 193 return; 194 } 195 196 if (!isMarked()) { 197 throw new IOException ("Resetting to an invalid mark"); 198 } 199 200 count = markedCount; 201 super.reset(); 202 } 203 markSupported()204 public boolean markSupported() { 205 if (closed) { 206 return false; 207 } 208 return super.markSupported(); 209 } 210 finalize()211 protected void finalize() throws Throwable { 212 try { 213 close(); 214 if (pi != null) 215 pi.close(); 216 } 217 finally { 218 // Call super class 219 super.finalize(); 220 } 221 } 222 } 223