/*
 * 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
/** * 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; } }