Fix parsing chapters with multiple null bytes

Previously, we relied on the string to fill the complete frame.
Some podcasts terminate the string early and leave some garbage in
the frame data. Skip that garbage, so that the reader is at a valid
frame header position when starting the next iteration.
This commit is contained in:
ByteHamster 2021-02-15 23:13:26 +01:00
parent aaeea78b37
commit 4f2dcc189c
3 changed files with 29 additions and 14 deletions

View File

@ -53,7 +53,7 @@ public class ChapterReader extends ID3Reader {
| ((int) startTimeSource[2] << 8) | startTimeSource[3];
currentChapter = new ID3Chapter(elementId.toString(), startTime);
skipBytes(input, 12);
return ID3Reader.ACTION_DONT_SKIP;
return ID3Reader.ACTION_DONT_SKIP; // Let reader discover the sub-frames
case FRAME_ID_TITLE:
if (currentChapter != null && currentChapter.getTitle() == null) {
StringBuilder title = new StringBuilder();
@ -62,7 +62,7 @@ public class ChapterReader extends ID3Reader {
.setTitle(title.toString());
Log.d(TAG, "Found title: " + currentChapter.getTitle());
return ID3Reader.ACTION_DONT_SKIP;
return ID3Reader.ACTION_SKIP;
}
break;
case FRAME_ID_LINK:
@ -79,7 +79,7 @@ public class ChapterReader extends ID3Reader {
Log.w(TAG, "Bad URL found in ID3 data");
}
return ID3Reader.ACTION_DONT_SKIP;
return ID3Reader.ACTION_SKIP;
}
break;
case FRAME_ID_PICTURE:
@ -109,7 +109,7 @@ public class ChapterReader extends ID3Reader {
}
skipBytes(input, length);
}
return ID3Reader.ACTION_DONT_SKIP;
return ID3Reader.ACTION_SKIP;
}
break;
}

View File

@ -20,7 +20,14 @@ public class ID3Reader {
private static final int ID3_LENGTH = 3;
private static final int FRAME_ID_LENGTH = 4;
private static final int ACTION_SKIP = 1;
/**
* Should skip remaining bytes of the current frame.
*/
static final int ACTION_SKIP = 1;
/**
* Should not skip remaining bytes of the current frame. Can be used to parse sub-frames.
*/
static final int ACTION_DONT_SKIP = 2;
private int readerPosition;
@ -49,12 +56,17 @@ public class ID3Reader {
if (checkForNullString(frameHeader.getId())) {
break;
}
int readerPositionBeforeFrame = input.getCount();
rc = onStartFrameHeader(frameHeader, input);
if (rc == ACTION_SKIP) {
if (frameHeader.getSize() + readerPosition > tagHeader.getSize()) {
break;
}
skipBytes(input, frameHeader.getSize());
int bytesAlreadyHandled = input.getCount() - readerPositionBeforeFrame;
int bytesLeftToSkip = frameHeader.getSize() - bytesAlreadyHandled;
if (bytesLeftToSkip > 0) {
skipBytes(input, bytesLeftToSkip);
}
}
}
}

View File

@ -1,17 +1,20 @@
package de.danoeh.antennapod.core.util.id3reader.model;
import androidx.annotation.NonNull;
public class FrameHeader extends Header {
private final char flags;
private final char flags;
public FrameHeader(String id, int size, char flags) {
super(id, size);
this.flags = flags;
}
public FrameHeader(String id, int size, char flags) {
super(id, size);
this.flags = flags;
}
@Override
public String toString() {
return String.format("FrameHeader [flags=%s, id=%s, size=%s]", Integer.toBinaryString(flags), id, Integer.toBinaryString(size));
@Override
@NonNull
public String toString() {
return String.format("FrameHeader [flags=%s, id=%s, size=%s]", Integer.toBinaryString(flags), id, size);
}
}