package freenet.client.async;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import com.onionnetworks.util.FileUtil;
import freenet.keys.Key;
import freenet.keys.KeyBlock;
import freenet.keys.KeyVerifyException;
public abstract class BinaryBlob {
public static final long BINARY_BLOB_MAGIC = 0x6d58249f72d67ed9L;
public static final short BINARY_BLOB_OVERALL_VERSION = 0;
public static void writeBinaryBlobHeader(DataOutputStream binaryBlobStream) throws IOException {
binaryBlobStream.writeLong(BinaryBlob.BINARY_BLOB_MAGIC);
binaryBlobStream.writeShort(BinaryBlob.BINARY_BLOB_OVERALL_VERSION);
}
public static void writeKey(DataOutputStream binaryBlobStream, KeyBlock block, Key key) throws IOException {
byte[] keyData = key.getKeyBytes();
byte[] headers = block.getRawHeaders();
byte[] data = block.getRawData();
byte[] pubkey = block.getPubkeyBytes();
writeBlobHeader(binaryBlobStream, BLOB_BLOCK, BLOB_BLOCK_VERSION,
9+keyData.length+headers.length+data.length+(pubkey==null?0:pubkey.length));
binaryBlobStream.writeShort(block.getKey().getType());
binaryBlobStream.writeByte(keyData.length);
binaryBlobStream.writeShort(headers.length);
binaryBlobStream.writeShort(data.length);
binaryBlobStream.writeShort(pubkey == null ? 0 : pubkey.length);
binaryBlobStream.write(keyData);
binaryBlobStream.write(headers);
binaryBlobStream.write(data);
if(pubkey != null)
binaryBlobStream.write(pubkey);
}
static final short BLOB_BLOCK = 1;
static final short BLOB_BLOCK_VERSION = 0;
static final short BLOB_END = 2;
static final short BLOB_END_VERSION = 0;
public static final String MIME_TYPE = "application/x-freenet-binary-blob";
static void writeBlobHeader(DataOutputStream binaryBlobStream, short type, short version, int length) throws IOException {
binaryBlobStream.writeInt(length);
binaryBlobStream.writeShort(type);
binaryBlobStream.writeShort(version);
}
public static void writeEndBlob(DataOutputStream binaryBlobStream) throws IOException {
writeBlobHeader(binaryBlobStream, BinaryBlob.BLOB_END, BinaryBlob.BLOB_END_VERSION, 0);
}
public static void readBinaryBlob(DataInputStream dis, BlockSet blocks, boolean tolerant) throws IOException, BinaryBlobFormatException {
long magic = dis.readLong();
if(magic != BinaryBlob.BINARY_BLOB_MAGIC)
throw new BinaryBlobFormatException("Bad magic");
short version = dis.readShort();
if(version != BinaryBlob.BINARY_BLOB_OVERALL_VERSION)
throw new BinaryBlobFormatException("Unknown overall version");
while(true) {
long blobLength;
try {
blobLength = dis.readInt() & 0xFFFFFFFFL;
} catch (EOFException e) {
// End of file
dis.close();
break;
}
short blobType = dis.readShort();
short blobVer = dis.readShort();
if(blobType == BinaryBlob.BLOB_END) {
dis.close();
break;
} else if(blobType == BinaryBlob.BLOB_BLOCK) {
if(blobVer != BinaryBlob.BLOB_BLOCK_VERSION)
// Even if tolerant, if we can't read a blob there probably isn't much we can do.
throw new BinaryBlobFormatException("Unknown block blob version");
if(blobLength < 9)
throw new BinaryBlobFormatException("Block blob too short");
short keyType = dis.readShort();
int keyLen = dis.readUnsignedByte();
int headersLen = dis.readUnsignedShort();
int dataLen = dis.readUnsignedShort();
int pubkeyLen = dis.readUnsignedShort();
int total = 9 + keyLen + headersLen + dataLen + pubkeyLen;
if(blobLength != total)
throw new BinaryBlobFormatException("Binary blob not same length as data: blobLength="+blobLength+" total="+total);
byte[] keyBytes = new byte[keyLen];
byte[] headersBytes = new byte[headersLen];
byte[] dataBytes = new byte[dataLen];
byte[] pubkeyBytes = new byte[pubkeyLen];
dis.readFully(keyBytes);
dis.readFully(headersBytes);
dis.readFully(dataBytes);
dis.readFully(pubkeyBytes);
KeyBlock block;
try {
block = Key.createBlock(keyType, keyBytes, headersBytes, dataBytes, pubkeyBytes);
} catch (KeyVerifyException e) {
throw new BinaryBlobFormatException("Invalid key: "+e.getMessage(), e);
}
blocks.add(block);
} else {
if(tolerant) {
FileUtil.skipFully(dis, blobLength);
} else {
throw new BinaryBlobFormatException("Unknown blob type: "+blobType);
}
}
}
}
}