332 lines
9.5 KiB
Java
332 lines
9.5 KiB
Java
/*
|
|
* Copyright (c) 2007, 2016, 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) {
|
|
try (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;
|
|
}
|
|
}
|