package org.bouncycastle.kmip.wire.binary; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.Date; import java.util.Iterator; import java.util.List; import org.bouncycastle.kmip.wire.KMIPEncodable; import org.bouncycastle.kmip.wire.KMIPEncoder; import org.bouncycastle.kmip.wire.KMIPItem; import org.bouncycastle.kmip.wire.KMIPType; import org.bouncycastle.util.Strings; public class BinaryEncoder implements KMIPEncoder { private final OutputStream out; public BinaryEncoder(OutputStream out) { this.out = out; } public void output(KMIPEncodable kmipEncodable) throws IOException { writeItem(kmipEncodable.toKMIPItem()); } private void writeItem(KMIPItem item) throws IOException { writeTag(item.getTag()); out.write(item.getType()); long length = item.getLength(); writeLength(length); switch (item.getType()) { case KMIPType.BIG_INTEGER: byte[] bigInt = ((BigInteger)item.getValue()).toByteArray(); int padLength = (int)(length - bigInt.length); if (padLength != 0) { byte pad = (byte)((bigInt[0] < 0) ? 0xff : 0x00); for (int p = 0; p != padLength; p++) { out.write(pad); } } out.write(bigInt); break; case KMIPType.BOOLEAN: writeLong(((Boolean)item.getValue()).booleanValue() ? 0x01 : 0x00); break; case KMIPType.BYTE_STRING: out.write(((byte[])item.getValue())); writePadFor(length); break; case KMIPType.DATE_TIME: writeLong(((Date)item.getValue()).getTime()); break; case KMIPType.ENUMERATION: writeInt(((Integer)item.getValue()).intValue()); break; case KMIPType.INTEGER: writeInt(((Integer)item.getValue()).intValue()); break; case KMIPType.INTERVAL: writeInt(((Long)item.getValue()).intValue()); break; case KMIPType.LONG_INTEGER: writeLong(((Long)item.getValue()).longValue()); break; case KMIPType.STRUCTURE: for (Iterator it = ((List)item.getValue()).iterator(); it.hasNext();) { writeItem((KMIPItem)it.next()); } break; case KMIPType.TEXT_STRING: out.write(Strings.toUTF8ByteArray((String)item.getValue())); writePadFor(length); break; } } private void writeLong(long l) throws IOException { out.write((int)(l >> 56)); out.write((int)(l >> 48)); out.write((int)(l >> 40)); out.write((int)(l >> 32)); out.write((int)(l >> 24)); out.write((int)(l >> 16)); out.write((int)(l >> 8)); out.write((int)l); } private void writeInt(int i) throws IOException { out.write(i >> 24); out.write(i >> 16); out.write(i >> 8); out.write(i); out.write(0); // padding out.write(0); out.write(0); out.write(0); } private void writeTag(int tag) throws IOException { out.write(tag >> 16); out.write(tag >> 8); out.write(tag); } private void writeLength(long length) throws IOException { out.write((int)(length >> 24)); out.write((int)(length >> 16)); out.write((int)(length >> 8)); out.write((int)length); } private void writePadFor(long length) throws IOException { int padLength = 8 - (int)(length % 8); if (padLength != 8) { for (int p = 0; p != padLength; p++) { out.write(0); } } } }