1 /* 2 * Copyright (c) 2007, 2016, 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 try (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 } 209 } 210 } else 211 out.write(array(), (int) arrayOffset(), (int) capacity()); 212 } 213 214 public InputStream getInputStream() { 215 if (root.file != null && root.buffer == null) { 216 try { 217 return new RandomFileInputStream(); 218 } catch (IOException e) { 219 //e.printStackTrace(); 220 return null; 221 } 222 } 223 return new ByteArrayInputStream(array(), 224 (int)arrayOffset(), (int)capacity()); 225 } 226 227 public ModelByteBuffer subbuffer(long beginIndex) { 228 return subbuffer(beginIndex, capacity()); 229 } 230 231 public ModelByteBuffer subbuffer(long beginIndex, long endIndex) { 232 return subbuffer(beginIndex, endIndex, false); 233 } 234 235 public ModelByteBuffer subbuffer(long beginIndex, long endIndex, 236 boolean independent) { 237 return new ModelByteBuffer(this, beginIndex, endIndex, independent); 238 } 239 240 public byte[] array() { 241 return root.buffer; 242 } 243 244 public long arrayOffset() { 245 if (root != this) 246 return root.arrayOffset() + offset; 247 return offset; 248 } 249 250 public long capacity() { 251 return len; 252 } 253 254 public ModelByteBuffer getRoot() { 255 return root; 256 } 257 258 public File getFile() { 259 return file; 260 } 261 262 public long getFilePointer() { 263 return fileoffset; 264 } 265 266 public static void loadAll(Collection<ModelByteBuffer> col) 267 throws IOException { 268 File selfile = null; 269 RandomAccessFile raf = null; 270 try { 271 for (ModelByteBuffer mbuff : col) { 272 mbuff = mbuff.root; 273 if (mbuff.file == null) 274 continue; 275 if (mbuff.buffer != null) 276 continue; 277 if (selfile == null || !selfile.equals(mbuff.file)) { 278 if (raf != null) { 279 raf.close(); 280 raf = null; 281 } 282 selfile = mbuff.file; 283 raf = new RandomAccessFile(mbuff.file, "r"); 284 } 285 raf.seek(mbuff.fileoffset); 286 byte[] buffer = new byte[(int) mbuff.capacity()]; 287 288 int read = 0; 289 int avail = buffer.length; 290 while (read != avail) { 291 if (avail - read > 65536) { 292 raf.readFully(buffer, read, 65536); 293 read += 65536; 294 } else { 295 raf.readFully(buffer, read, avail - read); 296 read = avail; 297 } 298 299 } 300 301 mbuff.buffer = buffer; 302 mbuff.offset = 0; 303 } 304 } finally { 305 if (raf != null) 306 raf.close(); 307 } 308 } 309 310 public void load() throws IOException { 311 if (root != this) { 312 root.load(); 313 return; 314 } 315 if (buffer != null) 316 return; 317 if (file == null) { 318 throw new IllegalStateException( 319 "No file associated with this ByteBuffer!"); 320 } 321 322 DataInputStream is = new DataInputStream(getInputStream()); 323 buffer = new byte[(int) capacity()]; 324 offset = 0; 325 is.readFully(buffer); 326 is.close(); 327 328 } 329 330 public void unload() { 331 if (root != this) { 332 root.unload(); 333 return; 334 } 335 if (file == null) { 336 throw new IllegalStateException( 337 "No file associated with this ByteBuffer!"); 338 } 339 root.buffer = null; 340 } 341 }