/*
* JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
*
* 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 jef.tools.zip;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
public class TarBuffer {
public TarBuffer(InputStream inStream) {
this(inStream, 10240);
}
public TarBuffer(InputStream inStream, int blockSize) {
this(inStream, blockSize, 512);
}
public TarBuffer(InputStream inStream, int blockSize, int recordSize) {
this.inStream = inStream;
outStream = null;
initialize(blockSize, recordSize);
}
public TarBuffer(OutputStream outStream) {
this(outStream, 10240);
}
public TarBuffer(OutputStream outStream, int blockSize) {
this(outStream, blockSize, 512);
}
public TarBuffer(OutputStream outStream, int blockSize, int recordSize) {
inStream = null;
this.outStream = outStream;
initialize(blockSize, recordSize);
}
private void initialize(int blockSize, int recordSize) {
debug = false;
this.blockSize = blockSize;
this.recordSize = recordSize;
recsPerBlock = this.blockSize / this.recordSize;
blockBuffer = new byte[this.blockSize];
if (inStream != null) {
currBlkIdx = -1;
currRecIdx = recsPerBlock;
} else {
currBlkIdx = 0;
currRecIdx = 0;
}
}
public int getBlockSize() {
return blockSize;
}
public int getRecordSize() {
return recordSize;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public boolean isEOFRecord(byte record[]) {
int i = 0;
for (int sz = getRecordSize(); i < sz; i++)
if (record[i] != 0)
return false;
return true;
}
public void skipRecord() throws IOException {
if (debug)
System.err.println("SkipRecord: recIdx = " + currRecIdx + " blkIdx = " + currBlkIdx);
if (inStream == null)
throw new IOException("reading (via skip) from an output buffer");
if (currRecIdx >= recsPerBlock && !readBlock()) {
return;
} else {
currRecIdx++;
return;
}
}
public byte[] readRecord() throws IOException {
if (debug)
System.err.println("ReadRecord: recIdx = " + currRecIdx + " blkIdx = " + currBlkIdx);
if (inStream == null)
throw new IOException("reading from an output buffer");
if (currRecIdx >= recsPerBlock && !readBlock()) {
return null;
} else {
byte result[] = new byte[recordSize];
System.arraycopy(blockBuffer, currRecIdx * recordSize, result, 0, recordSize);
currRecIdx++;
return result;
}
}
private boolean readBlock() throws IOException {
if (debug)
System.err.println("ReadBlock: blkIdx = " + currBlkIdx);
if (inStream == null)
throw new IOException("reading from an output buffer");
currRecIdx = 0;
int offset = 0;
int bytesNeeded = blockSize;
do {
if (bytesNeeded <= 0)
break;
long numBytes = inStream.read(blockBuffer, offset, bytesNeeded);
if (numBytes == -1L) {
if (offset == 0)
return false;
Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0);
break;
}
offset = (int) ((long) offset + numBytes);
bytesNeeded = (int) ((long) bytesNeeded - numBytes);
if (numBytes != (long) blockSize && debug)
System.err.println("ReadBlock: INCOMPLETE READ " + numBytes + " of " + blockSize + " bytes read.");
} while (true);
currBlkIdx++;
return true;
}
public int getCurrentBlockNum() {
return currBlkIdx;
}
public int getCurrentRecordNum() {
return currRecIdx - 1;
}
public void writeRecord(byte record[]) throws IOException {
if (debug)
System.err.println("WriteRecord: recIdx = " + currRecIdx + " blkIdx = " + currBlkIdx);
if (outStream == null)
throw new IOException("writing to an input buffer");
if (record.length != recordSize)
throw new IOException("record to write has length '" + record.length + "' which is not the record size of '" + recordSize + "'");
if (currRecIdx >= recsPerBlock)
writeBlock();
System.arraycopy(record, 0, blockBuffer, currRecIdx * recordSize, recordSize);
currRecIdx++;
}
public void writeRecord(byte buf[], int offset) throws IOException {
if (debug)
System.err.println("WriteRecord: recIdx = " + currRecIdx + " blkIdx = " + currBlkIdx);
if (outStream == null)
throw new IOException("writing to an input buffer");
if (offset + recordSize > buf.length)
throw new IOException("record has length '" + buf.length + "' with offset '" + offset + "' which is less than the record size of '" + recordSize + "'");
if (currRecIdx >= recsPerBlock)
writeBlock();
System.arraycopy(buf, offset, blockBuffer, currRecIdx * recordSize, recordSize);
currRecIdx++;
}
private void writeBlock() throws IOException {
if (debug)
System.err.println("WriteBlock: blkIdx = " + currBlkIdx);
if (outStream == null) {
throw new IOException("writing to an input buffer");
} else {
outStream.write(blockBuffer, 0, blockSize);
outStream.flush();
currRecIdx = 0;
currBlkIdx++;
return;
}
}
private void flushBlock() throws IOException {
if (debug)
System.err.println("TarBuffer.flushBlock() called.");
if (outStream == null)
throw new IOException("writing to an input buffer");
if (currRecIdx > 0)
writeBlock();
}
public void close() throws IOException {
if (debug)
System.err.println("TarBuffer.closeBuffer().");
if (outStream != null) {
flushBlock();
if (outStream != System.out && outStream != System.err) {
outStream.close();
outStream = null;
}
} else if (inStream != null && inStream != System.in) {
inStream.close();
inStream = null;
}
}
public static final int DEFAULT_RCDSIZE = 512;
public static final int DEFAULT_BLKSIZE = 10240;
private InputStream inStream;
private OutputStream outStream;
private byte blockBuffer[];
private int currBlkIdx;
private int currRecIdx;
private int blockSize;
private int recordSize;
private int recsPerBlock;
private boolean debug;
}