/*
* Copyright 2008 CoreMedia AG, Hamburg
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.coremedia.iso;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
/**
* A <code>FilterInputStream</code> enriched with helper methods to ease writing of
* Iso specific numbers and strings.
*/
public class IsoBufferWrapperImpl extends AbstractIsoBufferWrapper {
ByteBuffer[] parents;
int activeParent = 0;
public IsoBufferWrapperImpl(byte[] bytes) {
this(ByteBuffer.wrap(bytes));
}
public IsoBufferWrapperImpl(ByteBuffer parent) {
this.parents = new ByteBuffer[]{parent};
}
public IsoBufferWrapperImpl(ByteBuffer[] parents) {
this.parents = parents;
}
public IsoBufferWrapperImpl(List<ByteBuffer> parents) {
this.parents = parents.toArray(new ByteBuffer[parents.size()]);
}
public IsoBufferWrapperImpl(File file) throws IOException {
long filelength = file.length();
int sliceSize = 1024 * 1024 * 128;
RandomAccessFile raf = new RandomAccessFile(file, "r");
ArrayList<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
long i = 0;
while (i < filelength) {
if ((filelength - i) > sliceSize) {
ByteBuffer bb;
try {
bb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, i, sliceSize);//.slice();
} catch (IOException e1) {
try {
bb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, i, sliceSize);//.slice();
} catch (IOException e2) {
try {
bb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, i, sliceSize);//.slice();
} catch (IOException e3) {
bb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, i, sliceSize);//.slice();
}
}
}
buffers.add(bb);
i += sliceSize;
} else {
buffers.add(raf.getChannel().map(FileChannel.MapMode.READ_ONLY, i, filelength - i).slice());
i += filelength - i;
}
}
parents = buffers.toArray(new ByteBuffer[buffers.size()]);
raf.close();
}
public long position() {
if (activeParent >= 0) {
long pos = 0;
for (int i = 0; i < activeParent; i++) {
pos += parents[i].limit();
}
pos += parents[activeParent].position();
return pos;
} else {
return size();
}
}
public void position(long position) {
if (position == size()) {
activeParent = -1;
} else {
int current = 0;
while (position >= parents[current].limit()) {
position -= parents[current++].limit();
}
parents[current].position((int) position);
activeParent = current;
}
}
public long size() {
long size = 0;
for (ByteBuffer parent : parents) {
size += parent.limit();
}
return size;
}
public long remaining() {
if (activeParent == -1) {
return 0;
} else {
long remaining = 0;
for (int i = activeParent; i < parents.length; i++) {
remaining += parents[i].remaining();
}
return remaining;
}
}
public int read() {
if (parents[activeParent].remaining() == 0) {
if (parents.length > activeParent + 1) {
activeParent++;
parents[activeParent].rewind();
return read();
} else {
return -1;
}
}
int b = parents[activeParent].get();
return b < 0 ? b + 256 : b;
}
public int read(byte[] b) {
return read(b, 0, b.length);
}
public int read(byte[] b, int off, int len) {
if (parents[activeParent].remaining() >= len) {
parents[activeParent].get(b, off, len);
return len;
} else {
int curRemaining = parents[activeParent].remaining();
parents[activeParent].get(b, off, curRemaining);
activeParent++;
parents[activeParent].rewind();
return curRemaining + read(b, off + curRemaining, len - curRemaining);
}
}
public IsoBufferWrapper getSegment(long startPos, long length) {
long savePos = this.position();
ArrayList<ByteBuffer> segments = new ArrayList<ByteBuffer>();
position(startPos);
while (length > 0) {
ByteBuffer currentSlice = parents[activeParent].slice();
if (currentSlice.remaining() >= length) {
currentSlice.limit((int) length); // thats ok we tested in the line before
length -= length;
} else {
// ok use up current bytebuffer and jump to next
length -= currentSlice.remaining();
parents[++activeParent].rewind();
}
segments.add(currentSlice);
}
position(savePos);
return new IsoBufferWrapperImpl(segments.toArray(new ByteBuffer[segments.size()]));
}
}