- in SubripDecoder
- correctly: the regex
SUBRIP_TIMECODE makes this field optional
- incorrectly: the function
parseTimecode blindly assumes this field contains a non-null String value that can be parsed to a Long
minimal code to reproduces the problem:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Main {
public static void main(String[] args) {
run_test("00:00,000 --> 00:01,000");
}
private static final String SUBRIP_TIMECODE = "(?:(\\d+):)?(\\d+):(\\d+),(\\d+)";
private static final Pattern SUBRIP_TIMING_LINE = Pattern.compile("\\s*(" + SUBRIP_TIMECODE + ")\\s*-->\\s*(" + SUBRIP_TIMECODE + ")\\s*");
private static void run_test(String currentLine) {
Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
if (matcher.matches()) {
long start = parseTimecode(matcher, /* groupOffset= */ 1);
long end = parseTimecode(matcher, /* groupOffset= */ 6);
System.out.println("start: " + start);
System.out.println("end: " + end);
}
else {
System.out.println("no match");
}
}
private static long parseTimecode(Matcher matcher, int groupOffset) {
long timestampMs = Long.parseLong(matcher.group(groupOffset + 1)) * 60 * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 2)) * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 3)) * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 4));
return timestampMs * 1000;
}
}
output (stderr):
java.lang.NumberFormatException: null
at java.base/java.lang.Long.parseLong
fixed:
private static long parseTimecode(Matcher matcher, int groupOffset) {
long timestampMs = 0;
String groupVal;
// HOURS field is optional
groupVal = matcher.group(groupOffset + 1);
if (groupVal != null)
timestampMs += Long.parseLong(groupVal) * 60 * 60 * 1000;
// MINUTES field is required
groupVal = matcher.group(groupOffset + 2);
if (groupVal != null)
timestampMs += Long.parseLong(groupVal) * 60 * 1000;
// SECONDS field is required
groupVal = matcher.group(groupOffset + 3);
if (groupVal != null)
timestampMs += Long.parseLong(groupVal) * 1000;
// MILLISECONDS field is required
groupVal = matcher.group(groupOffset + 4);
if (groupVal != null)
timestampMs += Long.parseLong(groupVal);
// convert timecode from MILLISECONDS to MICROSECONDS
return timestampMs * 1000;
}
output (stdout):
SUBRIP_TIMECODEmakes this field optionalparseTimecodeblindly assumes this field contains a non-null String value that can be parsed to aLongminimal code to reproduces the problem:
output (stderr):
fixed:
output (stdout):