SubripDecoder extends SimpleSubtitleDecoder { @Override protected Subtitle decode(byte[] bytes, int length, boolean reset) { ArrayList<Cue> cues = new ArrayList<>(); LongArray cueTimesUs = new LongArray(); ParsableByteArray subripData = new ParsableByteArray(bytes, length); @Nullable String currentLine; while ((currentLine = subripData.readLine()) != null) { if (currentLine.length() == 0) { continue; } try { Integer.parseInt(currentLine); } catch (NumberFormatException e) { Log.w(TAG, "Skipping invalid index: " + currentLine); continue; } currentLine = subripData.readLine(); if (currentLine == null) { Log.w(TAG, "Unexpected end"); break; } Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine); if (matcher.matches()) { cueTimesUs.add(parseTimecode(matcher, 1)); cueTimesUs.add(parseTimecode(matcher, 6)); } else { Log.w(TAG, "Skipping invalid timing: " + currentLine); continue; } textBuilder.setLength(0); tags.clear(); currentLine = subripData.readLine(); while (!TextUtils.isEmpty(currentLine)) { if (textBuilder.length() > 0) { textBuilder.append("<br>"); } textBuilder.append(processLine(currentLine, tags)); currentLine = subripData.readLine(); } Spanned text = Html.fromHtml(textBuilder.toString()); @Nullable String alignmentTag = null; for (int i = 0; i < tags.size(); i++) { String tag = tags.get(i); if (tag.matches(SUBRIP_ALIGNMENT_TAG)) { alignmentTag = tag; break; } } cues.add(buildCue(text, alignmentTag)); cues.add(Cue.EMPTY); } Cue[] cuesArray = new Cue[cues.size()]; cues.toArray(cuesArray); long[] cueTimesUsArray = cueTimesUs.toArray(); return new SubripSubtitle(cuesArray, cueTimesUsArray); } SubripDecoder();   }
@Test public void testDecodeEmpty() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), EMPTY_FILE); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(0); assertThat(subtitle.getCues(0).isEmpty()).isTrue(); }
@Test public void testDecodeTypical() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_FILE); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(6); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); }
@Test public void testDecodeTypicalWithByteOrderMark() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), TYPICAL_WITH_BYTE_ORDER_MARK); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(6); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); }
@Test public void testDecodeTypicalExtraBlankLine() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), TYPICAL_EXTRA_BLANK_LINE); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(6); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); }
@Test public void testDecodeTypicalMissingTimecode() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), TYPICAL_MISSING_TIMECODE); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(4); assertTypicalCue1(subtitle, 0); assertTypicalCue3(subtitle, 2); }
@Test public void testDecodeTypicalMissingSequence() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), TYPICAL_MISSING_SEQUENCE); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(4); assertTypicalCue1(subtitle, 0); assertTypicalCue3(subtitle, 2); }
@Test public void testDecodeTypicalNegativeTimestamps() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray( ApplicationProvider.getApplicationContext(), TYPICAL_NEGATIVE_TIMESTAMPS); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(2); assertTypicalCue3(subtitle, 0); }
@Test public void testDecodeTypicalUnexpectedEnd() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_UNEXPECTED_END); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertThat(subtitle.getEventTimeCount()).isEqualTo(4); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); }
@Test public void testDecodeCueWithTag() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_WITH_TAGS); Subtitle subtitle = decoder.decode(bytes, bytes.length, false); assertTypicalCue1(subtitle, 0); assertTypicalCue2(subtitle, 2); assertTypicalCue3(subtitle, 4); assertThat(subtitle.getCues(subtitle.getEventTime(6)).get(0).text.toString()) .isEqualTo("This { \\an2} is not a valid tag due to the space after the opening bracket."); assertThat(subtitle.getCues(subtitle.getEventTime(8)).get(0).text.toString()) .isEqualTo("This is the fifth subtitle with multiple valid tags."); assertAlignmentCue(subtitle, 10, Cue.ANCHOR_TYPE_END, Cue.ANCHOR_TYPE_START); assertAlignmentCue(subtitle, 12, Cue.ANCHOR_TYPE_END, Cue.ANCHOR_TYPE_MIDDLE); assertAlignmentCue(subtitle, 14, Cue.ANCHOR_TYPE_END, Cue.ANCHOR_TYPE_END); assertAlignmentCue(subtitle, 16, Cue.ANCHOR_TYPE_MIDDLE, Cue.ANCHOR_TYPE_START); assertAlignmentCue(subtitle, 18, Cue.ANCHOR_TYPE_MIDDLE, Cue.ANCHOR_TYPE_MIDDLE); assertAlignmentCue(subtitle, 20, Cue.ANCHOR_TYPE_MIDDLE, Cue.ANCHOR_TYPE_END); assertAlignmentCue(subtitle, 22, Cue.ANCHOR_TYPE_START, Cue.ANCHOR_TYPE_START); assertAlignmentCue(subtitle, 24, Cue.ANCHOR_TYPE_START, Cue.ANCHOR_TYPE_MIDDLE); assertAlignmentCue(subtitle, 26, Cue.ANCHOR_TYPE_START, Cue.ANCHOR_TYPE_END); }