From ec74550cef3ff3c09ff30b79306e82d1bf14ae98 Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Tue, 12 May 2026 15:10:29 -0700 Subject: [PATCH] id3v2: tolerate odd-length UTF-16 text frames --- id3v2frames.go | 4 +++- id3v2frames_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 id3v2frames_test.go diff --git a/id3v2frames.go b/id3v2frames.go index 8397eba..aed9fd6 100644 --- a/id3v2frames.go +++ b/id3v2frames.go @@ -408,7 +408,9 @@ func decodeUTF16WithBOM(b []byte) (string, error) { func decodeUTF16(b []byte, bo binary.ByteOrder) (string, error) { if len(b)%2 != 0 { - return "", errors.New("invalid encoding: expected even number of bytes for UTF-16 encoded text") + // Some encoders append a stray trailing byte (often a null + // terminator); drop it rather than failing. + b = b[:len(b)-1] } s := make([]uint16, 0, len(b)/2) for i := 0; i < len(b); i += 2 { diff --git a/id3v2frames_test.go b/id3v2frames_test.go new file mode 100644 index 0000000..5aac462 --- /dev/null +++ b/id3v2frames_test.go @@ -0,0 +1,34 @@ +// Copyright 2024, David Howden +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tag + +import ( + "encoding/binary" + "testing" +) + +func TestDecodeUTF16OddLength(t *testing.T) { + // "AB" in UTF-16BE with a stray trailing null byte appended by the encoder. + b := []byte{0x00, 0x41, 0x00, 0x42, 0x00} + got, err := decodeUTF16(b, binary.BigEndian) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != "AB" { + t.Fatalf("got %q, want %q", got, "AB") + } +} + +func TestDecodeTextUTF16OddLength(t *testing.T) { + // encoding byte 0x01 (UTF-16 with BOM), little-endian BOM, "AB", stray null. + b := []byte{0x01, 0xFF, 0xFE, 0x41, 0x00, 0x42, 0x00, 0x00} + got, err := decodeText(b[0], b[1:]) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != "AB" { + t.Fatalf("got %q, want %q", got, "AB") + } +}