TarBufferpublic class TarBuffer extends Object The TarBuffer class implements the tar archive concept
of a buffered input stream. This concept goes back to the
days of blocked tape drives and special io devices. In the
Java universe, the only real function that this class
performs is to ensure that files have the correct "block"
size, or other tars will complain.
You should never have a need to access this class directly.
TarBuffers are created by Tar IO Streams. |
Fields Summary |
---|
public static final int | DEFAULT_RCDSIZEDefault record size | public static final int | DEFAULT_BLKSIZEDefault block size | 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 |
Constructors Summary |
---|
public TarBuffer(InputStream inStream)Constructor for a TarBuffer on an input stream.
this(inStream, TarBuffer.DEFAULT_BLKSIZE);
| public TarBuffer(InputStream inStream, int blockSize)Constructor for a TarBuffer on an input stream.
this(inStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
| public TarBuffer(InputStream inStream, int blockSize, int recordSize)Constructor for a TarBuffer on an input stream.
this.inStream = inStream;
this.outStream = null;
this.initialize(blockSize, recordSize);
| public TarBuffer(OutputStream outStream)Constructor for a TarBuffer on an output stream.
this(outStream, TarBuffer.DEFAULT_BLKSIZE);
| public TarBuffer(OutputStream outStream, int blockSize)Constructor for a TarBuffer on an output stream.
this(outStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
| public TarBuffer(OutputStream outStream, int blockSize, int recordSize)Constructor for a TarBuffer on an output stream.
this.inStream = null;
this.outStream = outStream;
this.initialize(blockSize, recordSize);
|
Methods Summary |
---|
public void | close()Close the TarBuffer. If this is an output buffer, also flush the
current block before closing.
if (this.debug) {
System.err.println("TarBuffer.closeBuffer().");
}
if (this.outStream != null) {
this.flushBlock();
if (this.outStream != System.out
&& this.outStream != System.err) {
this.outStream.close();
this.outStream = null;
}
} else if (this.inStream != null) {
if (this.inStream != System.in) {
this.inStream.close();
this.inStream = null;
}
}
| private void | flushBlock()Flush the current data block if it has any data in it.
if (this.debug) {
System.err.println("TarBuffer.flushBlock() called.");
}
if (this.outStream == null) {
throw new IOException("writing to an input buffer");
}
if (this.currRecIdx > 0) {
this.writeBlock();
}
| public int | getBlockSize()Get the TAR Buffer's block size. Blocks consist of multiple records.
return this.blockSize;
| public int | getCurrentBlockNum()Get the current block number, zero based.
return this.currBlkIdx;
| public int | getCurrentRecordNum()Get the current record number, within the current block, zero based.
Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.
return this.currRecIdx - 1;
| public int | getRecordSize()Get the TAR Buffer's record size.
return this.recordSize;
| private void | initialize(int blockSize, int recordSize)Initialization common to all constructors.
this.debug = false;
this.blockSize = blockSize;
this.recordSize = recordSize;
this.recsPerBlock = (this.blockSize / this.recordSize);
this.blockBuffer = new byte[this.blockSize];
if (this.inStream != null) {
this.currBlkIdx = -1;
this.currRecIdx = this.recsPerBlock;
} else {
this.currBlkIdx = 0;
this.currRecIdx = 0;
}
| public boolean | isEOFRecord(byte[] record)Determine if an archive record indicate End of Archive. End of
archive is indicated by a record that consists entirely of null bytes.
for (int i = 0, sz = this.getRecordSize(); i < sz; ++i) {
if (record[i] != 0) {
return false;
}
}
return true;
| private boolean | readBlock()
if (this.debug) {
System.err.println("ReadBlock: blkIdx = " + this.currBlkIdx);
}
if (this.inStream == null) {
throw new IOException("reading from an output buffer");
}
this.currRecIdx = 0;
int offset = 0;
int bytesNeeded = this.blockSize;
while (bytesNeeded > 0) {
long numBytes = this.inStream.read(this.blockBuffer, offset,
bytesNeeded);
//
// NOTE
// We have fit EOF, and the block is not full!
//
// This is a broken archive. It does not follow the standard
// blocking algorithm. However, because we are generous, and
// it requires little effort, we will simply ignore the error
// and continue as if the entire block were read. This does
// not appear to break anything upstream. We used to return
// false in this case.
//
// Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
//
if (numBytes == -1) {
if (offset == 0) {
// Ensure that we do not read gigabytes of zeros
// for a corrupt tar file.
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924
return false;
}
// However, just leaving the unread portion of the buffer dirty does
// cause problems in some cases. This problem is described in
// http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
//
// The solution is to fill the unused portion of the buffer with zeros.
Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0);
break;
}
offset += numBytes;
bytesNeeded -= numBytes;
if (numBytes != this.blockSize) {
if (this.debug) {
System.err.println("ReadBlock: INCOMPLETE READ "
+ numBytes + " of " + this.blockSize
+ " bytes read.");
}
}
}
this.currBlkIdx++;
return true;
| public byte[] | readRecord()Read a record from the input stream and return the data.
if (this.debug) {
System.err.println("ReadRecord: recIdx = " + this.currRecIdx
+ " blkIdx = " + this.currBlkIdx);
}
if (this.inStream == null) {
throw new IOException("reading from an output buffer");
}
if (this.currRecIdx >= this.recsPerBlock) {
if (!this.readBlock()) {
return null;
}
}
byte[] result = new byte[this.recordSize];
System.arraycopy(this.blockBuffer,
(this.currRecIdx * this.recordSize), result, 0,
this.recordSize);
this.currRecIdx++;
return result;
| public void | setDebug(boolean debug)Set the debugging flag for the buffer.
this.debug = debug;
| public void | skipRecord()Skip over a record on the input stream.
if (this.debug) {
System.err.println("SkipRecord: recIdx = " + this.currRecIdx
+ " blkIdx = " + this.currBlkIdx);
}
if (this.inStream == null) {
throw new IOException("reading (via skip) from an output buffer");
}
if (this.currRecIdx >= this.recsPerBlock) {
if (!this.readBlock()) {
return; // UNDONE
}
}
this.currRecIdx++;
| private void | writeBlock()Write a TarBuffer block to the archive.
if (this.debug) {
System.err.println("WriteBlock: blkIdx = " + this.currBlkIdx);
}
if (this.outStream == null) {
throw new IOException("writing to an input buffer");
}
this.outStream.write(this.blockBuffer, 0, this.blockSize);
this.outStream.flush();
this.currRecIdx = 0;
this.currBlkIdx++;
| public void | writeRecord(byte[] record)Write an archive record to the archive.
if (this.debug) {
System.err.println("WriteRecord: recIdx = " + this.currRecIdx
+ " blkIdx = " + this.currBlkIdx);
}
if (this.outStream == null) {
throw new IOException("writing to an input buffer");
}
if (record.length != this.recordSize) {
throw new IOException("record to write has length '"
+ record.length
+ "' which is not the record size of '"
+ this.recordSize + "'");
}
if (this.currRecIdx >= this.recsPerBlock) {
this.writeBlock();
}
System.arraycopy(record, 0, this.blockBuffer,
(this.currRecIdx * this.recordSize),
this.recordSize);
this.currRecIdx++;
| public void | writeRecord(byte[] buf, int offset)Write an archive record to the archive, where the record may be
inside of a larger array buffer. The buffer must be "offset plus
record size" long.
if (this.debug) {
System.err.println("WriteRecord: recIdx = " + this.currRecIdx
+ " blkIdx = " + this.currBlkIdx);
}
if (this.outStream == null) {
throw new IOException("writing to an input buffer");
}
if ((offset + this.recordSize) > buf.length) {
throw new IOException("record has length '" + buf.length
+ "' with offset '" + offset
+ "' which is less than the record size of '"
+ this.recordSize + "'");
}
if (this.currRecIdx >= this.recsPerBlock) {
this.writeBlock();
}
System.arraycopy(buf, offset, this.blockBuffer,
(this.currRecIdx * this.recordSize),
this.recordSize);
this.currRecIdx++;
|
|