%% -*- erlang-indent-level: 2 -*- %%========================================================================== %% From: Tomas Stejskal -- 23/02/2008 %% I've found some strange behavior regarding binary matching. The module's %% purpose is reading an id3 version 1 or version 1.1 tag from an mp3 bin. %% When I use the function read_v1_or_v11_tag on a mp3 binary containing %% version 1 tag, it returns an error. However, when the function %% read_only_v1_tag is applied on the same file, it reads the tag data %% correctly. The only difference between these two functions is that the %% former has an extra branch to read version 1.1 tag. %% This was a BEAM compiler bug which was fixed by a patch to beam_dead. %%========================================================================== -module(bs_id3). -export([test/0]). -define(BIN, <<84,65,71,68,117,154,105,232,107,121,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,68,97,110,105,101,108,32,76,97,110, 100,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,101,115,116, 32,79,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 50,48,48,48,50,48,48,48,32,45,32,66,101,115,116,32,79,102, 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,12>>). test() -> R1 = parse_only_v1_tag(?BIN), R2 = parse_v1_or_v11_tag(?BIN), %% io:format("~p\n~p\n", [R1, R2]), R1 = R2, % crash if not equal ok. parse_only_v1_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:30/binary, _Genre:8>>) -> {ok, {"ID3v1", [{title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_only_v1_tag(_) -> error. parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:28/binary, 0:8, Track:8, _Genre:8>>) -> {ok, {"ID3v1.1", [{track, Track}, {title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(<<"TAG", Title:30/binary, Artist:30/binary, Album:30/binary, _Year:4/binary, _Comment:30/binary, _Genre:8>>) -> {ok, {"ID3v1", [{title, trim(Title)}, {artist, trim(Artist)}, {album, trim(Album)}]}}; parse_v1_or_v11_tag(_) -> error. trim(Bin) -> list_to_binary(trim_blanks(binary_to_list(Bin))). trim_blanks(L) -> lists:reverse(skip_blanks_and_zero(lists:reverse(L))). skip_blanks_and_zero([$\s|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero([0|T]) -> skip_blanks_and_zero(T); skip_blanks_and_zero(L) -> L.