Charset: Latin1: when encoding, substitute '?' instead of truncating

String::data(Latin1) keeps only the low byte of each code point, so the
fast path wrote garbage for characters ISO 8859-1 cannot hold,
instead of '?' as documented in tcharset.h:
     * When encoding into a legacy code page, characters which cannot be
     * represented by the code page are replaced by '?'.
This commit is contained in:
MinnieTheMoocher
2026-10-31 10:58:01 +01:00
committed by Urs Fleisch
parent ff3b53670a
commit 66a523d685
2 changed files with 30 additions and 3 deletions
+18
View File
@@ -28,6 +28,7 @@
#include "taglib_config.h"
#include "tstring.h"
#include "tcharset.h"
#include "mpegfile.h"
#include "id3v1tag.h"
#include "id3v1genres.h"
@@ -64,6 +65,7 @@ class TestID3v1 : public CppUnit::TestFixture
CPPUNIT_TEST(testStripWhiteSpace);
CPPUNIT_TEST(testGenres);
CPPUNIT_TEST(testRenamedGenres);
CPPUNIT_TEST(testRenderLatin1Substitutes);
#ifdef TAGLIB_WITH_CHARSETTABLES
CPPUNIT_TEST(testAssumedCodePageDefaultIsLatin1);
CPPUNIT_TEST(testAssumedCodePage);
@@ -116,6 +118,22 @@ public:
CPPUNIT_ASSERT_EQUAL(129U, tag.genreNumber());
}
// Encoding into Latin1 has to substitute '?' for characters it cannot hold;
// truncating them to the low byte would write garbage into a file.
void testRenderLatin1Substitutes()
{
const ByteVector expected("A ? B", 5);
CPPUNIT_ASSERT_EQUAL(expected,
Charset::encode(kCyrillicArtistText, Charset::Type::Latin1));
// A fresh tag has no code page stated and is Latin1, so this is what
// render() writes for the artist field at offset 3 + 30.
ID3v1::Tag tag;
tag.setArtist(kCyrillicArtistText);
CPPUNIT_ASSERT_EQUAL(expected, tag.render().mid(33, 5));
}
#ifdef TAGLIB_WITH_CHARSETTABLES
//! A temporary MP3 file which is automatically deleted when it goes out of scope.
class ScopedMp3FileCopyWithId3v1Tag : public ScopedFileCopy