Skip to content

ID3v2: Fix double unsynchronisation of frames when the tag header flag is set#682

Open
attilagyorffy wants to merge 1 commit into
Serial-ATA:mainfrom
attilagyorffy:fix/id3v2-double-unsynchronisation
Open

ID3v2: Fix double unsynchronisation of frames when the tag header flag is set#682
attilagyorffy wants to merge 1 commit into
Serial-ATA:mainfrom
attilagyorffy:fix/id3v2-double-unsynchronisation

Conversation

@attilagyorffy

Copy link
Copy Markdown

Fixes #678.

The bug

When an ID3v2.4 tag sets the header unsynchronisation flag (0x80) and its frames also carry the per-frame unsynchronisation flag (0x02), lofty de-unsynchronises the frame content twice: once for the tag-level stream in parse_id3v2, and again for the frame flag in the frame reader. Each pass strips a 00 after every 0xFF, so an encoded FF 00 00 collapses to FF.

Text frames mostly survive this, but APIC pictures are binary and real JPEGs are full of FF 00 pairs, so covers come back corrupt and no longer decode. This is the shape Bandcamp's MP3 tagger writes.

The fix

Skip the frame-level unsynchronisation pass when the tag-level stream is already active, so frame content is decoded exactly once. The tag header's unsynchronisation flag is threaded down to the frame reader; the existing compression/encryption/plain arms then read the already-decoded bytes. Nonconforming writers that unsynchronise the whole tag without setting per-frame flags keep working, since that path is unchanged.

Test

Added unsynchronised_apic_is_decoded_once, which builds the exact tag shape from #678 and checks the APIC bytes survive the round-trip. It fails on main (FF 00 59 decodes to FF 59) and passes with the fix. The rest of the suite is unaffected.

Thanks to @zealsprince for the clear report and reproducer.

…g is set

When an ID3v2.4 tag sets the header unsynchronisation flag (0x80) and its
frames also carry the per-frame unsynchronisation flag (0x02), the tag-level
stream and the frame reader each de-unsynchronised the frame content, stripping
a `00` after every `0xFF` twice. Text frames survived, but binary APIC data
came back corrupt.

Skip the frame-level unsynchronisation pass when the tag-level stream is already
active, so frame content is decoded exactly once.

Fixes Serial-ATA#678

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ID3v2.4: frames are de-unsynchronised twice when both the tag header and frame unsync flags are set, corrupting APIC pictures

1 participant