How to read/parse stringj when here is no '3' mark?
ramunasjurgilas opened this issue · 3 comments
I am trying to parse binary file which begins with string (3 chars) with null termination.
The problem is, that this library requires to have prefix '3' before string, but in my binary file here is not this type of prefix.
My question how to parse string when here is no '3' prefix in front of string?
Failing error:
2021-11-09 12:50:22.141 11264-11264/com.example.binaryparser E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.binaryparser, PID: 11264
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.binaryparser/com.example.binaryparser.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'com.igormaznitsa.jbbp.model.JBBPAbstractField com.igormaznitsa.jbbp.model.JBBPFieldStruct.findFieldForType(java.lang.Class)' on a null object reference
Binary file structure is:
let prefix: String
let checksum: UInt32
let version: ECGFileVersion
let reserved: UInt8
let channelMask: UInt16
let sampleCount: UInt32
let frequency: UInt32
let reference: Int32
let gains: [Int32]
var samples: [Int] = [Int]()
To pars file prefix using this code:
final JBBPParser parser = JBBPParser.prepare("stringj;");
JBBPFieldStruct result = null;
try {
result = parser.parse(data);
} catch (IOException e) {
e.printStackTrace();
}
String dd = result.findFieldForType(JBBPFieldString.class).getAsString();
stringj is not null-ended format, if you have some specific data type thenm you can just provide new data type or my pascal asc ii reader from test
final class AscIIPascalString implements JBBPCustomFieldTypeProcessor {
private final String[] TYPES = new String[] {"asciistr"};
@Override
public String[] getCustomFieldTypes() {
return TYPES;
}
@Override
public boolean isAllowed(
final JBBPFieldTypeParameterContainer fieldType,
final String fieldName,
final int extraData,
final boolean isArray
) {
return extraData == 0;
}
@Override
public JBBPAbstractField readCustomFieldType(
final JBBPBitInputStream in,
final JBBPBitOrder bitOrder,
final int parserFlags,
final JBBPFieldTypeParameterContainer customTypeFieldInfo,
final JBBPNamedFieldInfo fieldName,
final int extraData,
final boolean readWholeStream,
final int arrayLength
) throws IOException {
if (arrayLength < 0) {
return new JBBPFieldString(fieldName, readPascalAscIIString(in));
} else {
final String[] loadedStrings;
if (readWholeStream) {
final List<String> strings = new ArrayList<>();
while (in.hasAvailableData()) {
strings.add(readPascalAscIIString(in));
}
loadedStrings = strings.toArray(new String[0]);
} else {
loadedStrings = new String[arrayLength];
for (int i = 0; i < arrayLength; i++) {
loadedStrings[i] = readPascalAscIIString(in);
}
}
return new JBBPFieldArrayString(fieldName, loadedStrings);
}
}
private String readPascalAscIIString(final JBBPBitInputStream in) throws IOException {
final byte[] charArray = in.readByteArray(in.readByte());
return new String(charArray, StandardCharsets.US_ASCII);
}
}it can be used final JBBPParser parserSingle = JBBPParser.prepare("asciistr str1; asciistr str2;", new AscIIPascalString());
did it help?
It is too much code for parsing null terminated string. Started using ByteBuffer and it is more simple. Here is Kotlin extension for doing it:
fun ByteBuffer.getString(): String {
var byteArrayStream = ByteArrayOutputStream()
while (hasRemaining()) {
var byte: Byte = get()
if (byte.toInt() == 0x0) {
break
}
byteArrayStream.write(byte.toInt())
}
return String(byteArrayStream.toByteArray())
}
