|  | /* | 
|  | * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. | 
|  | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|  | * | 
|  | * This code is free software; you can redistribute it and/or modify it | 
|  | * under the terms of the GNU General Public License version 2 only, as | 
|  | * published by the Free Software Foundation.  Oracle designates this | 
|  | * particular file as subject to the "Classpath" exception as provided | 
|  | * by Oracle in the LICENSE file that accompanied this code. | 
|  | * | 
|  | * This code is distributed in the hope that it will be useful, but WITHOUT | 
|  | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|  | * version 2 for more details (a copy is included in the LICENSE file that | 
|  | * accompanied this code). | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License version | 
|  | * 2 along with this work; if not, write to the Free Software Foundation, | 
|  | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|  | * | 
|  | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|  | * or visit www.oracle.com if you need additional information or have any | 
|  | * questions. | 
|  | */ | 
|  | package com.sun.media.sound; | 
|  |  | 
|  | import java.io.ByteArrayInputStream; | 
|  | import java.io.DataInputStream; | 
|  | import java.io.File; | 
|  | import java.io.IOException; | 
|  | import java.io.InputStream; | 
|  | import java.io.OutputStream; | 
|  | import java.io.RandomAccessFile; | 
|  | import java.util.Collection; | 
|  |  | 
|  | /** | 
|  | * This class is a pointer to a binary array either in memory or on disk. | 
|  | * | 
|  | * @author Karl Helgason | 
|  | */ | 
|  | public final class ModelByteBuffer { | 
|  |  | 
|  | private ModelByteBuffer root = this; | 
|  | private File file; | 
|  | private long fileoffset; | 
|  | private byte[] buffer; | 
|  | private long offset; | 
|  | private final long len; | 
|  |  | 
|  | private class RandomFileInputStream extends InputStream { | 
|  |  | 
|  | private final RandomAccessFile raf; | 
|  | private long left; | 
|  | private long mark = 0; | 
|  | private long markleft = 0; | 
|  |  | 
|  | RandomFileInputStream() throws IOException { | 
|  | raf = new RandomAccessFile(root.file, "r"); | 
|  | raf.seek(root.fileoffset + arrayOffset()); | 
|  | left = capacity(); | 
|  | } | 
|  |  | 
|  | public int available() throws IOException { | 
|  | if (left > Integer.MAX_VALUE) | 
|  | return Integer.MAX_VALUE; | 
|  | return (int)left; | 
|  | } | 
|  |  | 
|  | public synchronized void mark(int readlimit) { | 
|  | try { | 
|  | mark = raf.getFilePointer(); | 
|  | markleft = left; | 
|  | } catch (IOException e) { | 
|  | //e.printStackTrace(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public boolean markSupported() { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | public synchronized void reset() throws IOException { | 
|  | raf.seek(mark); | 
|  | left = markleft; | 
|  | } | 
|  |  | 
|  | public long skip(long n) throws IOException { | 
|  | if( n < 0) | 
|  | return 0; | 
|  | if (n > left) | 
|  | n = left; | 
|  | long p = raf.getFilePointer(); | 
|  | raf.seek(p + n); | 
|  | left -= n; | 
|  | return n; | 
|  | } | 
|  |  | 
|  | public int read(byte b[], int off, int len) throws IOException { | 
|  | if (len > left) | 
|  | len = (int)left; | 
|  | if (left == 0) | 
|  | return -1; | 
|  | len = raf.read(b, off, len); | 
|  | if (len == -1) | 
|  | return -1; | 
|  | left -= len; | 
|  | return len; | 
|  | } | 
|  |  | 
|  | public int read(byte[] b) throws IOException { | 
|  | int len = b.length; | 
|  | if (len > left) | 
|  | len = (int)left; | 
|  | if (left == 0) | 
|  | return -1; | 
|  | len = raf.read(b, 0, len); | 
|  | if (len == -1) | 
|  | return -1; | 
|  | left -= len; | 
|  | return len; | 
|  | } | 
|  |  | 
|  | public int read() throws IOException { | 
|  | if (left == 0) | 
|  | return -1; | 
|  | int b = raf.read(); | 
|  | if (b == -1) | 
|  | return -1; | 
|  | left--; | 
|  | return b; | 
|  | } | 
|  |  | 
|  | public void close() throws IOException { | 
|  | raf.close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private ModelByteBuffer(ModelByteBuffer parent, | 
|  | long beginIndex, long endIndex, boolean independent) { | 
|  | this.root = parent.root; | 
|  | this.offset = 0; | 
|  | long parent_len = parent.len; | 
|  | if (beginIndex < 0) | 
|  | beginIndex = 0; | 
|  | if (beginIndex > parent_len) | 
|  | beginIndex = parent_len; | 
|  | if (endIndex < 0) | 
|  | endIndex = 0; | 
|  | if (endIndex > parent_len) | 
|  | endIndex = parent_len; | 
|  | if (beginIndex > endIndex) | 
|  | beginIndex = endIndex; | 
|  | offset = beginIndex; | 
|  | len = endIndex - beginIndex; | 
|  | if (independent) { | 
|  | buffer = root.buffer; | 
|  | if (root.file != null) { | 
|  | file = root.file; | 
|  | fileoffset = root.fileoffset + arrayOffset(); | 
|  | offset = 0; | 
|  | } else | 
|  | offset = arrayOffset(); | 
|  | root = this; | 
|  | } | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer(byte[] buffer) { | 
|  | this.buffer = buffer; | 
|  | this.offset = 0; | 
|  | this.len = buffer.length; | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer(byte[] buffer, int offset, int len) { | 
|  | this.buffer = buffer; | 
|  | this.offset = offset; | 
|  | this.len = len; | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer(File file) { | 
|  | this.file = file; | 
|  | this.fileoffset = 0; | 
|  | this.len = file.length(); | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer(File file, long offset, long len) { | 
|  | this.file = file; | 
|  | this.fileoffset = offset; | 
|  | this.len = len; | 
|  | } | 
|  |  | 
|  | public void writeTo(OutputStream out) throws IOException { | 
|  | if (root.file != null && root.buffer == null) { | 
|  | InputStream is = getInputStream(); | 
|  | byte[] buff = new byte[1024]; | 
|  | int ret; | 
|  | while ((ret = is.read(buff)) != -1) | 
|  | out.write(buff, 0, ret); | 
|  | } else | 
|  | out.write(array(), (int) arrayOffset(), (int) capacity()); | 
|  | } | 
|  |  | 
|  | public InputStream getInputStream() { | 
|  | if (root.file != null && root.buffer == null) { | 
|  | try { | 
|  | return new RandomFileInputStream(); | 
|  | } catch (IOException e) { | 
|  | //e.printStackTrace(); | 
|  | return null; | 
|  | } | 
|  | } | 
|  | return new ByteArrayInputStream(array(), | 
|  | (int)arrayOffset(), (int)capacity()); | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer subbuffer(long beginIndex) { | 
|  | return subbuffer(beginIndex, capacity()); | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer subbuffer(long beginIndex, long endIndex) { | 
|  | return subbuffer(beginIndex, endIndex, false); | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer subbuffer(long beginIndex, long endIndex, | 
|  | boolean independent) { | 
|  | return new ModelByteBuffer(this, beginIndex, endIndex, independent); | 
|  | } | 
|  |  | 
|  | public byte[] array() { | 
|  | return root.buffer; | 
|  | } | 
|  |  | 
|  | public long arrayOffset() { | 
|  | if (root != this) | 
|  | return root.arrayOffset() + offset; | 
|  | return offset; | 
|  | } | 
|  |  | 
|  | public long capacity() { | 
|  | return len; | 
|  | } | 
|  |  | 
|  | public ModelByteBuffer getRoot() { | 
|  | return root; | 
|  | } | 
|  |  | 
|  | public File getFile() { | 
|  | return file; | 
|  | } | 
|  |  | 
|  | public long getFilePointer() { | 
|  | return fileoffset; | 
|  | } | 
|  |  | 
|  | public static void loadAll(Collection<ModelByteBuffer> col) | 
|  | throws IOException { | 
|  | File selfile = null; | 
|  | RandomAccessFile raf = null; | 
|  | try { | 
|  | for (ModelByteBuffer mbuff : col) { | 
|  | mbuff = mbuff.root; | 
|  | if (mbuff.file == null) | 
|  | continue; | 
|  | if (mbuff.buffer != null) | 
|  | continue; | 
|  | if (selfile == null || !selfile.equals(mbuff.file)) { | 
|  | if (raf != null) { | 
|  | raf.close(); | 
|  | raf = null; | 
|  | } | 
|  | selfile = mbuff.file; | 
|  | raf = new RandomAccessFile(mbuff.file, "r"); | 
|  | } | 
|  | raf.seek(mbuff.fileoffset); | 
|  | byte[] buffer = new byte[(int) mbuff.capacity()]; | 
|  |  | 
|  | int read = 0; | 
|  | int avail = buffer.length; | 
|  | while (read != avail) { | 
|  | if (avail - read > 65536) { | 
|  | raf.readFully(buffer, read, 65536); | 
|  | read += 65536; | 
|  | } else { | 
|  | raf.readFully(buffer, read, avail - read); | 
|  | read = avail; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | mbuff.buffer = buffer; | 
|  | mbuff.offset = 0; | 
|  | } | 
|  | } finally { | 
|  | if (raf != null) | 
|  | raf.close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public void load() throws IOException { | 
|  | if (root != this) { | 
|  | root.load(); | 
|  | return; | 
|  | } | 
|  | if (buffer != null) | 
|  | return; | 
|  | if (file == null) { | 
|  | throw new IllegalStateException( | 
|  | "No file associated with this ByteBuffer!"); | 
|  | } | 
|  |  | 
|  | DataInputStream is = new DataInputStream(getInputStream()); | 
|  | buffer = new byte[(int) capacity()]; | 
|  | offset = 0; | 
|  | is.readFully(buffer); | 
|  | is.close(); | 
|  |  | 
|  | } | 
|  |  | 
|  | public void unload() { | 
|  | if (root != this) { | 
|  | root.unload(); | 
|  | return; | 
|  | } | 
|  | if (file == null) { | 
|  | throw new IllegalStateException( | 
|  | "No file associated with this ByteBuffer!"); | 
|  | } | 
|  | root.buffer = null; | 
|  | } | 
|  | } |