@@ -1304,129 +1304,140 @@ fun parseTtml(audioMimeType: String?, lyricText: String): SemanticLyrics? {
13041304 val itunesTranslations = hashMapOf<String , HashMap <String , String >>()
13051305 val timer = TtmlTimeTracker (parser, hasItunesNamespace)
13061306 parser.nextTag()
1307- parser.require(XmlPullParser .START_TAG , tt, " head" )
1308- // TODO parse and reject based on https://www.w3.org/TR/2018/REC-ttml2-20181108/#feature-profile-version-2 to be compliant
1309- while (parser.nextTag() != XmlPullParser .END_TAG ) {
1310- if (parser.name == " metadata" ) {
1311- while (parser.nextTag() != XmlPullParser .END_TAG ) {
1312- if (parser.namespace == ttm && parser.name == " agent" ) {
1313- val id = parser.getAttributeValue(" http://www.w3.org/XML/1998/namespace" , " id" )
1314- val type = parser.getAttributeValue(" " , " type" )
1315- people.getOrPut(type) { mutableListOf () }.add(id)
1316- peopleToType[id] = type
1317- while (parser.nextTag() != XmlPullParser .END_TAG ) {
1318- if (parser.namespace == ttm && parser.name == " name" ) {
1319- // val type = parser.getAttributeValue("", "type")
1320- parser.nextAndThrowIfNotText()
1321- // val name = parser.text
1322- parser.nextAndThrowIfNotEnd()
1323- } else {
1324- throw XmlPullParserException (
1325- " expected <ttm:name>, got " +
1326- " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1327- " in <ttm:agent> in <metadata>"
1328- )
1307+ if (parser.eventType == XmlPullParser .END_TAG && parser.namespace == tt && parser.name == " tt" ) {
1308+ return null // a valid ttml file could have neither <head> or <body>, but it would be a weird one
1309+ }
1310+ parser.require(XmlPullParser .START_TAG , tt, null )
1311+ if (parser.name != " body" ) { // <head> is optional
1312+ parser.require(XmlPullParser .START_TAG , tt, " head" )
1313+ // TODO parse and reject based on https://www.w3.org/TR/2018/REC-ttml2-20181108/#feature-profile-version-2 to be compliant
1314+ while (parser.nextTag() != XmlPullParser .END_TAG ) {
1315+ if (parser.name == " metadata" ) {
1316+ while (parser.nextTag() != XmlPullParser .END_TAG ) {
1317+ if (parser.namespace == ttm && parser.name == " agent" ) {
1318+ val id =
1319+ parser.getAttributeValue(" http://www.w3.org/XML/1998/namespace" , " id" )
1320+ val type = parser.getAttributeValue(" " , " type" )
1321+ people.getOrPut(type) { mutableListOf () }.add(id)
1322+ peopleToType[id] = type
1323+ while (parser.nextTag() != XmlPullParser .END_TAG ) {
1324+ if (parser.namespace == ttm && parser.name == " name" ) {
1325+ // val type = parser.getAttributeValue("", "type")
1326+ parser.nextAndThrowIfNotText()
1327+ // val name = parser.text
1328+ parser.nextAndThrowIfNotEnd()
1329+ } else {
1330+ throw XmlPullParserException (
1331+ " expected <ttm:name>, got " +
1332+ " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1333+ " in <ttm:agent> in <metadata>"
1334+ )
1335+ }
13291336 }
1330- }
1331- } else if (parser.name == " iTunesMetadata " ) {
1332- while (parser.nextTag() != XmlPullParser . END_TAG ) {
1333- when (parser.name) {
1334- " songwriters " -> {
1335- while (parser.nextTag() != XmlPullParser . END_TAG ) {
1336- if (parser.name == " songwriter " ) {
1337- parser.nextAndThrowIfNotText()
1338- // val songwriter = parser.text
1339- parser.nextAndThrowIfNotEnd()
1340- } else {
1341- throw XmlPullParserException (
1342- " expected <songwriter>, got " +
1343- " < ${(parser.prefix?.plus( " : " ) ? : " " ) + parser.name} > " +
1344- " in <songwriters> in <iTunesMetadata> "
1345- )
1337+ } else if (parser.name == " iTunesMetadata " ) {
1338+ while (parser.nextTag() != XmlPullParser . END_TAG ) {
1339+ when (parser.name ) {
1340+ " songwriters " -> {
1341+ while (parser.nextTag() != XmlPullParser . END_TAG ) {
1342+ if (parser.name == " songwriter " ) {
1343+ parser.nextAndThrowIfNotText()
1344+ // val songwriter = parser.text
1345+ parser.nextAndThrowIfNotEnd()
1346+ } else {
1347+ throw XmlPullParserException (
1348+ " expected <songwriter>, got " +
1349+ " < ${(parser.prefix?.plus( " : " ) ? : " " ) + parser.name} > " +
1350+ " in <songwriters> in <iTunesMetadata> "
1351+ )
1352+ }
13461353 }
13471354 }
1348- }
13491355
1350- " audio" -> {
1351- val role = parser.getAttributeValue(null , " role" )
1352- if (when (role) {
1353- " spatial" -> audioMimeType == MimeTypes .AUDIO_AC3 ||
1354- audioMimeType == MimeTypes .AUDIO_E_AC3 ||
1355- audioMimeType == MimeTypes .AUDIO_AC4
1356- // ext- are Gramophone extensions
1357- " ext-not-spatial" -> ! (audioMimeType == MimeTypes .AUDIO_AC3 ||
1358- audioMimeType == MimeTypes .AUDIO_E_AC3 ||
1359- audioMimeType == MimeTypes .AUDIO_AC4 )
1360-
1361- " ext-always" -> true
1362- else -> throw XmlPullParserException (
1363- " unsupported offset " +
1364- " role $role , can't decide whether to apply offset"
1356+ " audio" -> {
1357+ val role = parser.getAttributeValue(null , " role" )
1358+ if (when (role) {
1359+ " spatial" -> audioMimeType == MimeTypes .AUDIO_AC3 ||
1360+ audioMimeType == MimeTypes .AUDIO_E_AC3 ||
1361+ audioMimeType == MimeTypes .AUDIO_AC4
1362+ // ext- are Gramophone extensions
1363+ " ext-not-spatial" -> ! (audioMimeType == MimeTypes .AUDIO_AC3 ||
1364+ audioMimeType == MimeTypes .AUDIO_E_AC3 ||
1365+ audioMimeType == MimeTypes .AUDIO_AC4 )
1366+
1367+ " ext-always" -> true
1368+ else -> throw XmlPullParserException (
1369+ " unsupported offset " +
1370+ " role $role , can't decide whether to apply offset"
1371+ )
1372+ }
1373+ ) {
1374+ val parsed = timer.parseTimestampMs(
1375+ parser.getAttributeValue(
1376+ null ,
1377+ " lyricOffset"
1378+ ), 0L , true
13651379 )
1380+ if (timer.audioOffset != null )
1381+ timer.audioOffset = timer.audioOffset!! + (parsed ? : 0L )
1382+ else
1383+ timer.audioOffset = parsed
13661384 }
1367- ) {
1368- val parsed = timer.parseTimestampMs(
1369- parser.getAttributeValue(
1370- null ,
1371- " lyricOffset"
1372- ), 0L , true
1373- )
1374- if (timer.audioOffset != null )
1375- timer.audioOffset = timer.audioOffset!! + (parsed ? : 0L )
1376- else
1377- timer.audioOffset = parsed
1385+ parser.nextAndThrowIfNotEnd()
13781386 }
1379- parser.nextAndThrowIfNotEnd()
1380- }
13811387
1382- " translations" -> {
1383- while (parser.nextTag() != XmlPullParser .END_TAG ) {
1384- if (parser.name == " translation" ) {
1385- val type = parser.getAttributeValue(null , " type" )
1386- if (type != " subtitle" ) {
1387- throw XmlPullParserException (" unsupported translation type $type " )
1388- }
1389- val lang = parser.getAttributeValue(
1390- " http://www.w3.org/XML/1998/namespace" ,
1391- " lang"
1392- )
1393- val out = hashMapOf<String , String >()
1394- while (parser.nextTag() != XmlPullParser .END_TAG ) {
1395- if (parser.name == " text" ) {
1396- val `for ` = parser.getAttributeValue(null , " for" )
1397- ? : throw XmlPullParserException (" missing attribute for at $parser " )
1398- parser.nextAndThrowIfNotText()
1399- out [`for `] = parser.text
1400- parser.nextAndThrowIfNotEnd()
1401- } else {
1402- throw XmlPullParserException (
1403- " expected <text>, got " +
1404- " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1405- " in <translation> in <translations> in <iTunesMetadata>"
1406- )
1388+ " translations" -> {
1389+ while (parser.nextTag() != XmlPullParser .END_TAG ) {
1390+ if (parser.name == " translation" ) {
1391+ val type = parser.getAttributeValue(null , " type" )
1392+ if (type != " subtitle" ) {
1393+ throw XmlPullParserException (" unsupported translation type $type " )
1394+ }
1395+ val lang = parser.getAttributeValue(
1396+ " http://www.w3.org/XML/1998/namespace" ,
1397+ " lang"
1398+ )
1399+ val out = hashMapOf<String , String >()
1400+ while (parser.nextTag() != XmlPullParser .END_TAG ) {
1401+ if (parser.name == " text" ) {
1402+ val `for ` =
1403+ parser.getAttributeValue(null , " for" )
1404+ ? : throw XmlPullParserException (" missing attribute for at $parser " )
1405+ parser.nextAndThrowIfNotText()
1406+ out [`for `] = parser.text
1407+ parser.nextAndThrowIfNotEnd()
1408+ } else {
1409+ throw XmlPullParserException (
1410+ " expected <text>, got " +
1411+ " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1412+ " in <translation> in <translations> in <iTunesMetadata>"
1413+ )
1414+ }
14071415 }
1416+ itunesTranslations[lang] = out
1417+ } else {
1418+ throw XmlPullParserException (
1419+ " expected <translation>, got " +
1420+ " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1421+ " in <translations> in <iTunesMetadata>"
1422+ )
14081423 }
1409- itunesTranslations[lang] = out
1410- } else {
1411- throw XmlPullParserException (
1412- " expected <translation>, got " +
1413- " <${(parser.prefix?.plus(" :" ) ? : " " ) + parser.name} > " +
1414- " in <translations> in <iTunesMetadata>"
1415- )
14161424 }
14171425 }
1418- }
14191426
1420- else -> parser.skipToEndOfTag()
1421- } // there are some others
1422- }
1423- } else parser.skipToEndOfTag()
1424- }
1425- } else // probably <styling> or <layout>
1426- parser.skipToEndOfTag()
1427+ else -> parser.skipToEndOfTag()
1428+ } // there are some others
1429+ }
1430+ } else parser.skipToEndOfTag()
1431+ }
1432+ } else // probably <styling> or <layout>
1433+ parser.skipToEndOfTag()
1434+ }
1435+ parser.require(XmlPullParser .END_TAG , tt, " head" )
1436+ parser.nextTag()
1437+ if (parser.eventType == XmlPullParser .END_TAG && parser.namespace == tt && parser.name == " tt" ) {
1438+ return null // a valid ttml file could have no <body>, but it would be a weird one
1439+ }
14271440 }
1428- parser.require(XmlPullParser .END_TAG , tt, " head" )
1429- parser.nextTag()
14301441 parser.require(XmlPullParser .START_TAG , tt, " body" )
14311442 val state = TtmlParserState (parser, timer)
14321443 state.parse()
0 commit comments