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