mirror of
https://github.com/taglib/taglib.git
synced 2026-11-06 22:48:48 -05:00
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:
committed by
Urs Fleisch
parent
ff3b53670a
commit
66a523d685
@@ -73,9 +73,18 @@ ByteVector TagLib::Charset::encode(const String &s, Type type)
|
||||
if(type == Type::UTF8)
|
||||
return s.data(String::UTF8);
|
||||
|
||||
// Fast path for likely Latin-1 case
|
||||
if(type == Type::Latin1)
|
||||
return s.data(String::Latin1);
|
||||
if(type == Type::Latin1) {
|
||||
// String::data(Latin1) casts every code point to char, keeping only the
|
||||
// low byte, so the '?' substitution the header promises is done here.
|
||||
ByteVector data(s.size(), '?');
|
||||
char *p = data.data();
|
||||
for(const wchar_t c : s) {
|
||||
if(c < 256)
|
||||
*p = static_cast<char>(c);
|
||||
++p;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
const auto *entry = detail::entryForCodePage(static_cast<unsigned int>(type));
|
||||
if(!entry)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user