@Override public Subtitle parse(InputStream inputStream) throws IOException { try { XmlPullParser xmlParser = xmlParserFactory.newPullParser(); Map<String, TtmlStyle> globalStyles = new HashMap<>(); xmlParser.setInput(inputStream, null); TtmlSubtitle ttmlSubtitle = null; LinkedList<TtmlNode> nodeStack = new LinkedList<>(); int unsupportedNodeDepth = 0; int eventType = xmlParser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { TtmlNode parent = nodeStack.peekLast(); if (unsupportedNodeDepth == 0) { String name = xmlParser.getName(); if (eventType == XmlPullParser.START_TAG) { if (!isSupportedTag(name)) { Log.i(TAG, "Ignoring unsupported tag: " + xmlParser.getName()); unsupportedNodeDepth++; } else if (TtmlNode.TAG_HEAD.equals(name)) { parseHeader(xmlParser, globalStyles); } else { try { TtmlNode node = parseNode(xmlParser, parent); nodeStack.addLast(node); if (parent != null) { parent.addChild(node); } } catch (ParserException e) { if (strictParsing) { throw e; } else { Log.w(TAG, "Suppressing parser error", e); // Treat the node (and by extension, all of its children) as unsupported. unsupportedNodeDepth++; } } } } else if (eventType == XmlPullParser.TEXT) { parent.addChild(TtmlNode.buildTextNode(xmlParser.getText())); } else if (eventType == XmlPullParser.END_TAG) { if (xmlParser.getName().equals(TtmlNode.TAG_TT)) { ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast(), globalStyles); } nodeStack.removeLast(); } } else { if (eventType == XmlPullParser.START_TAG) { unsupportedNodeDepth++; } else if (eventType == XmlPullParser.END_TAG) { unsupportedNodeDepth--; } } xmlParser.next(); eventType = xmlParser.getEventType(); } return ttmlSubtitle; } catch (XmlPullParserException xppe) { throw new ParserException("Unable to parse source", xppe); } }
private TtmlNode parseNode(XmlPullParser parser, TtmlNode parent) throws ParserException { long duration = 0; long startTime = TtmlNode.UNDEFINED_TIME; long endTime = TtmlNode.UNDEFINED_TIME; String[] styleIds = null; int attributeCount = parser.getAttributeCount(); TtmlStyle style = parseStyleAttributes(parser, null); for (int i = 0; i < attributeCount; i++) { String attr = ParserUtil.removeNamespacePrefix(parser.getAttributeName(i)); String value = parser.getAttributeValue(i); if (attr.equals(ATTR_BEGIN)) { startTime = parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE); } else if (attr.equals(ATTR_END)) { endTime = parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE); } else if (attr.equals(ATTR_DURATION)) { duration = parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE); } else if (attr.equals(ATTR_STYLE)) { // IDREFS: potentially multiple space delimited ids String[] ids = parseStyleIds(value); if (ids.length > 0) { styleIds = ids; } } else { // Do nothing. } } if (parent != null && parent.startTimeUs != TtmlNode.UNDEFINED_TIME) { if (startTime != TtmlNode.UNDEFINED_TIME) { startTime += parent.startTimeUs; } if (endTime != TtmlNode.UNDEFINED_TIME) { endTime += parent.startTimeUs; } } if (endTime == TtmlNode.UNDEFINED_TIME) { if (duration > 0) { // Infer the end time from the duration. endTime = startTime + duration; } else if (parent != null && parent.endTimeUs != TtmlNode.UNDEFINED_TIME) { // If the end time remains unspecified, then it should be inherited from the parent. endTime = parent.endTimeUs; } } return TtmlNode.buildNode(parser.getName(), startTime, endTime, style, styleIds); }