package org.archive.format.gzip; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.archive.util.ByteOp; public class GZIPFExtraRecord implements GZIPConstants { private byte[] name = null; private byte[] value = null; public GZIPFExtraRecord() { } public GZIPFExtraRecord(byte[] name, long intVal) throws GZIPFormatException { if(name.length != GZIP_FEXTRA_NAME_BYTES) { throw new GZIPFormatException("FExtra name is 2 bytes"); } this.name = name; value = new byte[4]; ByteOp.writeInt(value, 0, intVal); } public GZIPFExtraRecord(byte[] name, byte[] value) throws GZIPFormatException { if(name.length != GZIP_FEXTRA_NAME_BYTES) { throw new GZIPFormatException("FExtra name is 2 bytes"); } if(value != null) { if(value.length > GZIP_FEXTRA_VALUE_MAX_LENGTH) { throw new GZIPFormatException("FExtra value max is " + GZIP_FEXTRA_VALUE_MAX_LENGTH + " bytes"); } } this.name = name; this.value = value; } public boolean matchesName(byte name[]) { if(name == null) { return false; } if(this.name == null) { return false; } return ByteOp.cmp(this.name, name); } public byte[] getName() { return name; } public byte[] getValue() { return value; } public void setValue(byte[] value) { this.value = value; } /** * @return the number of bytes used by this record: * 0 - if the name is not set (invalid record), * 4 - if the value is not set (name + 0-length value) * 4 + value.length - if both are set (valid record, name + non-empty value) */ public int length() { if(name == null) { return 0; } if(value == null) { return GZIP_FEXTRA_VALUE_IDX; } return GZIP_FEXTRA_VALUE_IDX + value.length; } public void writeTo(byte[] buf, int offset) { if(buf.length - offset < length()) { throw new IndexOutOfBoundsException(); } buf[offset+0] = name[0]; buf[offset+1] = name[1]; if(value == null) { ByteOp.writeShort(buf, offset + GZIP_FEXTRA_LENGTH_IDX, 0); } else { ByteOp.writeShort(buf, offset + GZIP_FEXTRA_LENGTH_IDX, value.length); System.arraycopy(value, GZIP_FEXTRA_VALUE_IDX, buf, offset + GZIP_FEXTRA_LENGTH_IDX, value.length); } } public void writeTo(OutputStream os) throws IOException { if((name == null) || (value == null)) { return; } os.write(name); if(value == null) { ByteOp.writeShort(os, 0); } else { ByteOp.writeShort(os, value.length); os.write(value); } } public int read(InputStream is) throws IOException { byte tmpName[] = null; byte tmpVal[] = null; int valLen = 0; tmpName = ByteOp.readNBytes(is, GZIP_FEXTRA_NAME_BYTES); valLen = ByteOp.readShort(is); if(valLen > 0) { tmpVal = ByteOp.readNBytes(is, valLen); } name = tmpName; value = tmpVal; return GZIP_FEXTRA_NAME_BYTES + BYTES_IN_SHORT + valLen; } public int read(byte[] buf, int offset) throws GZIPFormatException, IOException { byte tmpName[] = null; byte tmpVal[] = null; int valLen = 0; int remaining = buf.length - offset; if(remaining < GZIP_FEXTRA_VALUE_IDX) { throw new GZIPFormatException("Short bytes for FExtra field"); } tmpName = ByteOp.copy(buf, offset, GZIP_FEXTRA_NAME_BYTES); valLen = ByteOp.bytesToShort(buf, offset + GZIP_FEXTRA_LENGTH_IDX); remaining -= GZIP_FEXTRA_NAME_IDX; if(valLen > 0) { if(valLen > remaining) { throw new GZIPFormatException("Short bytes for FExtra value"); } tmpVal = ByteOp.copy(buf,offset + GZIP_FEXTRA_VALUE_IDX,valLen); } name = tmpName; value = tmpVal; return GZIP_FEXTRA_VALUE_IDX + valLen; } }