Skip to content

Commit

Permalink
WestRidgeSystems#442 - WIP attempt at processing InputStream
Browse files Browse the repository at this point in the history
  • Loading branch information
Curtis Ruck authored and Curtis Ruck committed Dec 16, 2022
1 parent d898f53 commit 47b124f
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
52 changes: 52 additions & 0 deletions api/src/main/java/org/jmisb/api/klv/BerDecoder.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package org.jmisb.api.klv;

import java.io.IOException;
import java.io.InputStream;

/** Decode data using Basic Encoding Rules (BER). */
public class BerDecoder {

private BerDecoder() {}

/**
Expand Down Expand Up @@ -77,4 +81,52 @@ public static BerField decode(byte[] data, int offset, boolean isOid)

return new BerField(length, value);
}

public static BerField decode(InputStream is, boolean isOid) throws IOException {
if (!isOid) {
return decodeBer(is);
}

return decodeBerOid(is);
}

private static BerField decodeBer(InputStream is) throws IOException {
int length = is.read();

if ((length & 0x80) == 0) {
// BER Short Form. If the first bit of the BER is 0 then the BER is 1-byte.
return new BerField(1, length);
}

// BER Long Form (variable length)
int berLength = length & 0x7f;
int fullBerSize = berLength + 1;
byte[] data = new byte[berLength];
int read = is.read(data, 0, data.length);
if (read != data.length) {
throw new IllegalArgumentException("BER parsing ran out of bytes");
}
int len = 0;
for (int i = 0; i < berLength; ++i) {
int b = 0x00FF & data[i];
len = (len << 8) | b;
}
length = len;

return new BerField(fullBerSize, length);
}

private static BerField decodeBerOid(InputStream is) throws IOException {
int read;
int value = 0;
int length = 0;
do {
read = is.read();
int highbits = (value << 7);
int lowbits = (read & 0x7F);
value = highbits + lowbits;
length++;
} while ((read & 0x80) == 0x80);
return new BerField(length, value);
}
}
58 changes: 58 additions & 0 deletions api/src/main/java/org/jmisb/api/klv/KlvParser.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.jmisb.api.klv;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.jmisb.api.common.KlvParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -13,6 +17,60 @@ public class KlvParser {

private KlvParser() {}

public static void parseStream(
InputStream is,
Consumer<IMisbMessage> handler,
Consumer<KlvParseException> exceptionHandler)
throws KlvParseException {

// reusable key array to minimize garbage
byte[] key = new byte[UniversalLabel.LENGTH];

try {
while (true) {
ByteArrayOutputStream out = new ByteArrayOutputStream();

// Read the UniversalLabel
int read = is.read(key, 0, key.length);
if (read < 0) {
break;
}
if (read != key.length) {
throw new KlvParseException(
"Read " + read + " bytes when expected " + key.length);
}
out.write(key);

// Read the payload length
BerField length = BerDecoder.decode(is, false);
out.write(BerEncoder.encode(length.getValue()));

// Read the payload
byte[] payload = new byte[length.getValue()];
read = is.read(payload, 0, payload.length);
if (read == 0) {
break;
}
if (read != payload.length) {
throw new KlvParseException(
"Read " + read + " bytes when expected " + key.length);
}
out.write(payload);

// hand off the IMisbMessage
byte[] buf = out.toByteArray();
try {
IMisbMessage msg = MisbMessageFactory.getInstance().handleMessage(buf);
handler.accept(msg);
} catch (KlvParseException e) {
exceptionHandler.accept(e);
}
}
} catch (IOException e) {
throw new KlvParseException("IOException during stream parsing");
}
}

/**
* Parse a byte array containing one or more {@link IMisbMessage}s.
*
Expand Down

0 comments on commit 47b124f

Please sign in to comment.