public void readChapterSubFrame(@NonNull FrameHeader frameHeader, @NonNull Chapter chapter)
            throws IOException, ID3ReaderException {
        Log.d(TAG, "Handling subframe: " + frameHeader.toString());
        int frameStartPosition = getPosition();
        switch (frameHeader.getId()) {
            case FRAME_ID_TITLE:
                chapter.setTitle(readEncodingAndString(frameHeader.getSize()));
                Log.d(TAG, "Found title: " + chapter.getTitle());
                break;
            case FRAME_ID_LINK:
                readEncodingAndString(frameHeader.getSize()); // skip description
                String url = readIsoStringNullTerminated(frameStartPosition + frameHeader.getSize() - getPosition());
                try {
                    String decodedLink = URLDecoder.decode(url, "ISO-8859-1");
                    chapter.setLink(decodedLink);
                    Log.d(TAG, "Found link: " + chapter.getLink());
                } catch (IllegalArgumentException iae) {
                    Log.w(TAG, "Bad URL found in ID3 data");
                }
                break;
            case FRAME_ID_PICTURE:
                byte encoding = readByte();
                String mime = readIsoStringNullTerminated(frameHeader.getSize());
                byte type = readByte();
                String description = readEncodedString(encoding, frameHeader.getSize());
                Log.d(TAG, "Found apic: " + mime + "," + description);
                if (MIME_IMAGE_URL.equals(mime)) {
                    String link = readIsoStringNullTerminated(frameHeader.getSize());
                    Log.d(TAG, "Link: " + link);
                    if (TextUtils.isEmpty(chapter.getImageUrl()) || type == IMAGE_TYPE_COVER) {
                        chapter.setImageUrl(link);
                    }
                } else {
                    int alreadyConsumed = getPosition() - frameStartPosition;
                    int rawImageDataLength = frameHeader.getSize() - alreadyConsumed;
                    if (TextUtils.isEmpty(chapter.getImageUrl()) || type == IMAGE_TYPE_COVER) {
                        chapter.setImageUrl(EmbeddedChapterImage.makeUrl(getPosition(), rawImageDataLength));
                    }
                }
                break;
            default:
                Log.d(TAG, "Unknown chapter sub-frame.");
                break;
        }

        // Skip garbage to fill frame completely
        // This also asserts that we are not reading too many bytes from this frame.
        int alreadyConsumed = getPosition() - frameStartPosition;
        skipBytes(frameHeader.getSize() - alreadyConsumed);
    }
@Test
    public void testReadTitleWithGarbage() throws IOException, ID3ReaderException {
        byte[] titleSubframeContent = {
                ID3Reader.ENCODING_ISO,
                'A', // Title
                0, // Null-terminated
                42, 42, 42, 42 // Garbage, should be ignored
        };
        FrameHeader header = new FrameHeader(ChapterReader.FRAME_ID_TITLE, titleSubframeContent.length, (short) 0);
        CountingInputStream inputStream = new CountingInputStream(new ByteArrayInputStream(titleSubframeContent));
        ChapterReader reader = new ChapterReader(inputStream);
        Chapter chapter = new Chapter();
        reader.readChapterSubFrame(header, chapter);
        assertEquals("A", chapter.getTitle());

        // Should skip the garbage and point to the next frame
        assertEquals(titleSubframeContent.length, reader.getPosition());
    }