1 7 8 package javax.imageio.stream; 9 10 import java.util.ArrayList ; 11 import java.io.InputStream ; 12 import java.io.OutputStream ; 13 import java.io.IOException ; 14 15 39 class MemoryCache { 40 41 private static final int BUFFER_LENGTH = 8192; 42 43 private ArrayList cache = new ArrayList (); 44 45 private long cacheStart = 0L; 46 47 50 private long length = 0L; 51 52 private byte[] getCacheBlock(long blockNum) throws IOException { 53 long blockOffset = blockNum - cacheStart; 54 if (blockOffset > Integer.MAX_VALUE) { 55 throw new IOException ("Cache addressing limit exceeded!"); 58 } 59 return (byte[])cache.get((int)blockOffset); 60 } 61 62 68 public long loadFromStream(InputStream stream, long pos) 69 throws IOException { 70 if (pos < length) { 72 return pos; 73 } 74 75 int offset = (int)(length % BUFFER_LENGTH); 76 byte [] buf = null; 77 78 long len = pos - length; 79 if (offset != 0) { 80 buf = getCacheBlock(length/BUFFER_LENGTH); 81 } 82 83 while (len > 0) { 84 if (buf == null) { 85 try { 86 buf = new byte[BUFFER_LENGTH]; 87 } catch (OutOfMemoryError e) { 88 throw new IOException ("No memory left for cache!"); 89 } 90 offset = 0; 91 } 92 93 int left = BUFFER_LENGTH - offset; 94 int nbytes = (int)Math.min(len, (long)left); 95 nbytes = stream.read(buf, offset, nbytes); 96 if (nbytes == -1) { 97 return length; } 99 100 if (offset == 0) { 101 cache.add(buf); 102 } 103 104 len -= nbytes; 105 length += nbytes; 106 offset += nbytes; 107 108 if (offset >= BUFFER_LENGTH) { 109 buf = null; 112 } 113 } 114 115 return pos; 116 } 117 118 129 public void writeToStream(OutputStream stream, long pos, long len) 130 throws IOException { 131 if (pos + len > length) { 132 throw new IndexOutOfBoundsException ("Argument out of cache"); 133 } 134 if ((pos < 0) || (len < 0)) { 135 throw new IndexOutOfBoundsException ("Negative pos or len"); 136 } 137 if (len == 0) { 138 return; 139 } 140 141 long bufIndex = pos/BUFFER_LENGTH; 142 if (bufIndex < cacheStart) { 143 throw new IndexOutOfBoundsException ("pos already disposed"); 144 } 145 int offset = (int)(pos % BUFFER_LENGTH); 146 147 byte[] buf = getCacheBlock(bufIndex++); 148 while (len > 0) { 149 if (buf == null) { 150 buf = getCacheBlock(bufIndex++); 151 offset = 0; 152 } 153 int nbytes = (int)Math.min(len, (long)(BUFFER_LENGTH - offset)); 154 stream.write(buf, offset, nbytes); 155 buf = null; 156 len -= nbytes; 157 } 158 } 159 160 163 private void pad(long pos) throws IOException { 164 long currIndex = cacheStart + cache.size() - 1; 165 long lastIndex = pos/BUFFER_LENGTH; 166 long numNewBuffers = lastIndex - currIndex; 167 for (long i = 0; i < numNewBuffers; i++) { 168 try { 169 cache.add(new byte[BUFFER_LENGTH]); 170 } catch (OutOfMemoryError e) { 171 throw new IOException ("No memory left for cache!"); 172 } 173 } 174 } 175 176 191 public void write(byte[] b, int off, int len, long pos) 192 throws IOException { 193 if (b == null) { 194 throw new NullPointerException ("b == null!"); 195 } 196 if ((off < 0) || (len < 0) || (pos < 0) || 198 (off + len > b.length) || (off + len < 0)) { 199 throw new IndexOutOfBoundsException (); 200 } 201 202 long lastPos = pos + len - 1; 204 if (lastPos >= length) { 205 pad(lastPos); 206 length = lastPos + 1; 207 } 208 209 int offset = (int)(pos % BUFFER_LENGTH); 211 while (len > 0) { 212 byte[] buf = getCacheBlock(pos/BUFFER_LENGTH); 213 int nbytes = Math.min(len, BUFFER_LENGTH - offset); 214 System.arraycopy(b, off, buf, offset, nbytes); 215 216 pos += nbytes; 217 off += nbytes; 218 len -= nbytes; 219 offset = 0; } 221 } 222 223 234 public void write(int b, long pos) throws IOException { 235 if (pos < 0) { 236 throw new ArrayIndexOutOfBoundsException ("pos < 0"); 237 } 238 239 if (pos >= length) { 241 pad(pos); 242 length = pos + 1; 243 } 244 245 byte[] buf = getCacheBlock(pos/BUFFER_LENGTH); 247 int offset = (int)(pos % BUFFER_LENGTH); 248 buf[offset] = (byte)b; 249 } 250 251 256 public long getLength() { 257 return length; 258 } 259 260 265 public int read(long pos) throws IOException { 266 if (pos >= length) { 267 return -1; 268 } 269 270 byte[] buf = getCacheBlock(pos/BUFFER_LENGTH); 271 if (buf == null) { 272 return -1; 273 } 274 275 return buf[(int)(pos % BUFFER_LENGTH)] & 0xff; 276 } 277 278 290 public void read(byte[] b, int off, int len, long pos) 291 throws IOException { 292 if (b == null) { 293 throw new NullPointerException ("b == null!"); 294 } 295 if ((off < 0) || (len < 0) || (pos < 0) || 297 (off + len > b.length) || (off + len < 0)) { 298 throw new IndexOutOfBoundsException (); 299 } 300 if (pos + len > length) { 301 throw new IndexOutOfBoundsException (); 302 } 303 304 long index = pos/BUFFER_LENGTH; 305 int offset = (int)pos % BUFFER_LENGTH; 306 while (len > 0) { 307 int nbytes = Math.min(len, BUFFER_LENGTH - offset); 308 byte[] buf = getCacheBlock(index++); 309 System.arraycopy(buf, offset, b, off, nbytes); 310 311 len -= nbytes; 312 off += nbytes; 313 offset = 0; } 315 } 316 317 324 public void disposeBefore(long pos) { 325 long index = pos/BUFFER_LENGTH; 326 if (index < cacheStart) { 327 throw new IndexOutOfBoundsException ("pos already disposed"); 328 } 329 long numBlocks = Math.min(index - cacheStart, cache.size()); 330 for (long i = 0; i < numBlocks; i++) { 331 cache.remove(0); 332 } 333 this.cacheStart = index; 334 } 335 336 341 public void reset() { 342 cache.clear(); 343 cacheStart = 0; 344 length = 0L; 345 } 346 } 347 | Popular Tags |