crotwell / seisFile

A library for reading and writing seismic file formats in java.
GNU Lesser General Public License v3.0
27 stars 20 forks source link

Control header record is not continued properly #3

Closed grabarczyk-t closed 7 years ago

grabarczyk-t commented 7 years ago

The attached file LGCD_signal001958.part.txt contains a few control header records. Reading it with SeisFile library causes an exception:

java.lang.NumberFormatException: For input string: "20D"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at edu.sc.seis.seisFile.mseed.ControlRecord.readSingleControlRecord(ControlRecord.java:89)
    at edu.sc.seis.seisFile.mseed.ControlRecord.readControlRecord(ControlRecord.java:28)
    at edu.sc.seis.seisFile.mseed.SeedRecord.read(SeedRecord.java:70)

The reason for that seem to be wrong handling of continued records. The record with sequNum 3 ends with the following data: (note the two spaces at the end)

047  78  

It should be added to the SeedRecord as a PartialBlockette, but the problem is that it is just ignored.

changing lines 79-140 in class edu.sc.seis.seisFile.mseed.ControlRecord to:

while (recordSize == 0 || currOffset <= recordSize-7) {
    String typeStr;
    byte[] typeBytes = new byte[3];
    if (recordSize == 0 || currOffset < recordSize - 3) {
        inStream.readFully(typeBytes);
        typeStr = new String(typeBytes);
        currOffset += typeBytes.length;
    } else {
        typeStr = THREESPACE;
    }
    // New blockette's type and length did not fit in this record. We assume the rest of the record is garbage
    if (typeStr.equals(THREESPACE)) break;

    if (recordSize != 0 && currOffset >= recordSize - 4) {
        throw new SeedFormatException("Blockette’s type/length section is split across records");
    }

    int type = Integer.parseInt(typeStr.trim());
    byte[] lengthBytes = new byte[4];
    inStream.readFully(lengthBytes);
    String lengthStr = new String(lengthBytes);
    currOffset+= lengthBytes.length;
    int length = Integer.parseInt(lengthStr.trim());
    if (recordSize == 0 || length+currOffset-7 < recordSize) {
        readBytes = new byte[length-7];
    } else {
        // not enough bytes left in record to fill blockette
        readBytes = new byte[recordSize - currOffset];
    }
    inStream.readFully(readBytes);
    currOffset+= readBytes.length;
    byte[] fullBlocketteBytes = new byte[7+readBytes.length]; // less than length in case of continuation
    System.arraycopy(typeBytes,
            0,
            fullBlocketteBytes,
            0,
            3);
    System.arraycopy(lengthBytes,
            0,
            fullBlocketteBytes,
            3,
            4);
    System.arraycopy(readBytes,
            0,
            fullBlocketteBytes,
            7,
            readBytes.length);
    Blockette b;
    if (length == fullBlocketteBytes.length) {
        b = SeedRecord.getBlocketteFactory().parseBlockette(type,
                fullBlocketteBytes,
                true);
    } else {
        //special case for partial blockette continued in next record
        b = new PartialBlockette(type, fullBlocketteBytes, true, 0, length);
    }
    if (b instanceof ControlRecordLengthBlockette) {
        recordSize = ((ControlRecordLengthBlockette)b).getLogicalRecordLength();
    }

    controlRec.addBlockette(b);
}

seems to fix the problem

crotwell commented 7 years ago

Looks reasonable, thanks for figuring this out.

Would you be willing to submit this as a pull request? That would make it a lot easier for me.

And would you be ok with including this file being used as data for a test case?

grabarczyk-t commented 7 years ago

Would you be willing to submit this as a pull request?

Sure. I will do that shortly

would you be ok with including this file being used as data for a test case?

I have to ask the owner of that file first. I will let you know when i get the answer

grabarczyk-t commented 7 years ago

I asked about the file, and its ok to use it here as test data

crotwell commented 7 years ago

fixed in 1.7.3