class IntelHexRecordReader {

    public static IntelHexRecord readRecord(String line) {
        line = line.replaceAll("\\s+", "");
        if (line.length() < DATA_START + CHECKSUM_LENGTH) {
            throw new IllegalArgumentException("line too short to contain record");
        }
        String recordMark = line.substring(RECORD_MARK_START, RECORD_MARK_END);
        if (!":".equals(recordMark)) {
            throw new IllegalArgumentException("line does not start with record mark (:)");
        }
        String recordLengthString = line.substring(RECORD_LENGTH_START, RECORD_LENGTH_END);
        int recordLength;
        try {
            recordLength = Integer.parseInt(recordLengthString, 16);
        }
        catch (NumberFormatException e) {
            throw new IllegalArgumentException("error parsing record length: "
                    + e.getMessage());
        }
        String loadOffsetString = line.substring(LOAD_OFFSET_START, LOAD_OFFSET_END);
        int loadOffset;
        try {
            loadOffset = Integer.parseInt(loadOffsetString, 16);
        }
        catch (NumberFormatException e) {
            throw new IllegalArgumentException("error parsing load offset: "
                    + e.getMessage());
        }
        String recordTypeString = line.substring(RECORD_TYPE_START, RECORD_TYPE_END);
        int recordType;
        try {
            recordType = Integer.parseInt(recordTypeString, 16);
        }
        catch (NumberFormatException e) {
            throw new IllegalArgumentException("error parsing record type: "
                    + e.getMessage());
        }
        final int data_end = DATA_START + recordLength * 2;
        final int checksum_start = data_end;
        final int checksum_end = checksum_start + CHECKSUM_LENGTH;
        if (line.length() != checksum_end) {
            throw new IllegalArgumentException("line invalid length to contain record with record length "
                    + recordLength);
        }
        String dataString = line.substring(DATA_START, data_end);
        byte[] data = convertData(dataString);
        String checksumString = line.substring(checksum_start, checksum_end);
        int checksum;
        try {
            checksum = Integer.parseInt(checksumString, 16);
        }
        catch (NumberFormatException e) {
            throw new IllegalArgumentException("error parsing checksum: "
                    + e.getMessage());
        }
        return new IntelHexRecord(recordLength, loadOffset, recordType, data, checksum);
    }

}