1 /* 2 * Copyright (c) 2007, 2013, 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 com.sun.media.sound; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.DataInputStream; 30 import java.io.File; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.OutputStream; 34 import java.io.RandomAccessFile; 35 import java.util.Collection; 36 37 /** 38 * This class is a pointer to a binary array either in memory or on disk. 39 * 40 * @author Karl Helgason 41 */ 42 public final class ModelByteBuffer { 43 44 private ModelByteBuffer root = this; 45 private File file; 46 private long fileoffset; 47 private byte[] buffer; 48 private long offset; 49 private final long len; 50 51 private class RandomFileInputStream extends InputStream { 52 53 private final RandomAccessFile raf; 54 private long left; 55 private long mark = 0; 56 private long markleft = 0; 57 58 RandomFileInputStream() throws IOException { 59 raf = new RandomAccessFile(root.file, "r"); 60 raf.seek(root.fileoffset + arrayOffset()); 61 left = capacity(); 62 } 63 64 @Override 65 public int available() throws IOException { 66 if (left > Integer.MAX_VALUE) 67 return Integer.MAX_VALUE; 68 return (int)left; 69 } 70 71 @Override 72 public synchronized void mark(int readlimit) { 73 try { 74 mark = raf.getFilePointer(); 75 markleft = left; 76 } catch (IOException e) { 77 //e.printStackTrace(); 78 } 79 } 80 81 @Override 82 public boolean markSupported() { 83 return true; 84 } 85 86 @Override 87 public synchronized void reset() throws IOException { 88 raf.seek(mark); 89 left = markleft; 90 } 91 92 @Override 93 public long skip(long n) throws IOException { 94 if( n < 0) 95 return 0; 96 if (n > left) 97 n = left; 98 long p = raf.getFilePointer(); 99 raf.seek(p + n); 100 left -= n; 101 return n; 102 } 103 104 @Override 105 public int read(byte b[], int off, int len) throws IOException { 106 if (len > left) 107 len = (int)left; 108 if (left == 0) 109 return -1; 110 len = raf.read(b, off, len); 111 if (len == -1) 112 return -1; 113 left -= len; 114 return len; 115 } 116 117 @Override 118 public int read(byte[] b) throws IOException { 119 int len = b.length; 120 if (len > left) 121 len = (int)left; 122 if (left == 0) 123 return -1; 124 len = raf.read(b, 0, len); 125 if (len == -1) 126 return -1; 127 left -= len; 128 return len; 129 } 130 131 @Override 132 public int read() throws IOException { 133 if (left == 0) 134 return -1; 135 int b = raf.read(); 136 if (b == -1) 137 return -1; 138 left--; 139 return b; 140 } 141 142 @Override 143 public void close() throws IOException { 144 raf.close(); 145 } 146 } 147 148 private ModelByteBuffer(ModelByteBuffer parent, 149 long beginIndex, long endIndex, boolean independent) { 150 this.root = parent.root; 151 this.offset = 0; 152 long parent_len = parent.len; 153 if (beginIndex < 0) 154 beginIndex = 0; 155 if (beginIndex > parent_len) 156 beginIndex = parent_len; 157 if (endIndex < 0) 158 endIndex = 0; 159 if (endIndex > parent_len) 160 endIndex = parent_len; 161 if (beginIndex > endIndex) 162 beginIndex = endIndex; 163 offset = beginIndex; 164 len = endIndex - beginIndex; 165 if (independent) { 166 buffer = root.buffer; 167 if (root.file != null) { 168 file = root.file; 169 fileoffset = root.fileoffset + arrayOffset(); 170 offset = 0; 171 } else 172 offset = arrayOffset(); 173 root = this; 174 } 175 } 176 177 public ModelByteBuffer(byte[] buffer) { 178 this.buffer = buffer; 179 this.offset = 0; 180 this.len = buffer.length; 181 } 182 183 public ModelByteBuffer(byte[] buffer, int offset, int len) { 184 this.buffer = buffer; 185 this.offset = offset; 186 this.len = len; 187 } 188 189 public ModelByteBuffer(File file) { 190 this.file = file; 191 this.fileoffset = 0; 192 this.len = file.length(); 193 } 194 195 public ModelByteBuffer(File file, long offset, long len) { 196 this.file = file; 197 this.fileoffset = offset; 198 this.len = len; 199 } 200 201 public void writeTo(OutputStream out) throws IOException { 202 if (root.file != null && root.buffer == null) { 203 InputStream is = getInputStream(); 204 byte[] buff = new byte[1024]; 205 int ret; 206 while ((ret = is.read(buff)) != -1) 207 out.write(buff, 0, ret); 208 } else 209 out.write(array(), (int) arrayOffset(), (int) capacity()); 210 } 211 212 public InputStream getInputStream() { 213 if (root.file != null && root.buffer == null) { 214 try { 215 return new RandomFileInputStream(); 216 } catch (IOException e) { 217 //e.printStackTrace(); 218 return null; 219 } 220 } 221 return new ByteArrayInputStream(array(), 222 (int)arrayOffset(), (int)capacity()); 223 } 224 225 public ModelByteBuffer subbuffer(long beginIndex) { 226 return subbuffer(beginIndex, capacity()); 227 } 228 229 public ModelByteBuffer subbuffer(long beginIndex, long endIndex) { 230 return subbuffer(beginIndex, endIndex, false); 231 } 232 233 public ModelByteBuffer subbuffer(long beginIndex, long endIndex, 234 boolean independent) { 235 return new ModelByteBuffer(this, beginIndex, endIndex, independent); 236 } 237 238 public byte[] array() { 239 return root.buffer; 240 } 241 242 public long arrayOffset() { 243 if (root != this) 244 return root.arrayOffset() + offset; 245 return offset; 246 } 247 248 public long capacity() { 249 return len; 250 } 251 252 public ModelByteBuffer getRoot() { 253 return root; 254 } 255 256 public File getFile() { 257 return file; 258 } 259 260 public long getFilePointer() { 261 return fileoffset; 262 } 263 264 public static void loadAll(Collection<ModelByteBuffer> col) 265 throws IOException { 266 File selfile = null; 267 RandomAccessFile raf = null; 268 try { 269 for (ModelByteBuffer mbuff : col) { 270 mbuff = mbuff.root; 271 if (mbuff.file == null) 272 continue; 273 if (mbuff.buffer != null) 274 continue; 275 if (selfile == null || !selfile.equals(mbuff.file)) { 276 if (raf != null) { 277 raf.close(); 278 raf = null; 279 } 280 selfile = mbuff.file; 281 raf = new RandomAccessFile(mbuff.file, "r"); 282 } 283 raf.seek(mbuff.fileoffset); 284 byte[] buffer = new byte[(int) mbuff.capacity()]; 285 286 int read = 0; 287 int avail = buffer.length; 288 while (read != avail) { 289 if (avail - read > 65536) { 290 raf.readFully(buffer, read, 65536); 291 read += 65536; 292 } else { 293 raf.readFully(buffer, read, avail - read); 294 read = avail; 295 } 296 297 } 298 299 mbuff.buffer = buffer; 300 mbuff.offset = 0; 301 } 302 } finally { 303 if (raf != null) 304 raf.close(); 305 } 306 } 307 308 public void load() throws IOException { 309 if (root != this) { 310 root.load(); 311 return; 312 } 313 if (buffer != null) 314 return; 315 if (file == null) { 316 throw new IllegalStateException( 317 "No file associated with this ByteBuffer!"); 318 } 319 320 DataInputStream is = new DataInputStream(getInputStream()); 321 buffer = new byte[(int) capacity()]; 322 offset = 0; 323 is.readFully(buffer); 324 is.close(); 325 326 } 327 328 public void unload() { 329 if (root != this) { 330 root.unload(); 331 return; 332 } 333 if (file == null) { 334 throw new IllegalStateException( 335 "No file associated with this ByteBuffer!"); 336 } 337 root.buffer = null; 338 } 339 }