6#include <c++utilities/conversion/conversionexception.h>
7#include <c++utilities/conversion/stringbuilder.h>
10#include <initializer_list>
60 CPP_UTILITIES_UNUSED(diag)
62 stream.read(buffer, 128);
63 if (buffer[0] != 0x54 || buffer[1] != 0x41 || buffer[2] != 0x47) {
67 readValue(m_title, 30, buffer + 3);
68 readValue(m_artist, 30, buffer + 33);
69 readValue(m_album, 30, buffer + 63);
70 readValue(m_year, 4, buffer + 93);
71 const auto is11 = buffer[125] == 0;
73 readValue(m_comment, 28, buffer + 97);
76 readValue(m_comment, 30, buffer + 97);
79 readValue(m_comment, is11 ? 28 : 30, buffer + 97);
81 m_trackPos.assignPosition(
PositionInSet(*
reinterpret_cast<char *
>(buffer + 126), 0));
83 m_genre.assignStandardGenreIndex(*
reinterpret_cast<unsigned char *
>(buffer + 127));
95 static const string context(
"making ID3v1 tag");
100 stream.write(buffer, 3);
103 writeValue(m_title, 30, buffer, stream, diag);
104 writeValue(m_artist, 30, buffer, stream, diag);
105 writeValue(m_album, 30, buffer, stream, diag);
106 writeValue(m_year, 4, buffer, stream, diag);
107 writeValue(m_comment, 28, buffer, stream, diag);
115 if (!m_trackPos.isEmpty()) {
117 const auto position(m_trackPos.toPositionInSet().position());
118 if (position < 0x00 || position > 0xFF) {
119 throw ConversionException();
121 buffer[1] =
static_cast<char>(position);
122 }
catch (
const ConversionException &) {
124 DiagLevel::Warning,
"Track position field can not be set because given value can not be converted appropriately.", context);
130 const auto genreIndex(m_genre.toStandardGenreIndex());
131 if (genreIndex < 0x00 || genreIndex > 0xFF) {
132 throw ConversionException();
134 buffer[2] =
static_cast<char>(genreIndex);
135 }
catch (
const ConversionException &) {
137 "Genre field can not be set because given value can not be converted to a standard genre number supported by ID3v1.", context);
140 stream.write(buffer, 3);
205 return !m_title.isEmpty();
207 return !m_artist.isEmpty();
209 return !m_album.isEmpty();
210 return !m_year.isEmpty();
212 return !m_comment.isEmpty();
214 return !m_trackPos.isEmpty();
216 return !m_genre.isEmpty();
224 m_title.clearDataAndMetadata();
225 m_artist.clearDataAndMetadata();
226 m_album.clearDataAndMetadata();
227 m_year.clearDataAndMetadata();
228 m_comment.clearDataAndMetadata();
229 m_trackPos.clearDataAndMetadata();
230 m_genre.clearDataAndMetadata();
235 auto count = std::size_t(0);
236 for (
const auto &
value : std::initializer_list<const TagValue *>{ &m_title, &m_artist, &m_album, &m_year, &m_comment, &m_trackPos, &m_genre }) {
237 if (!
value->isEmpty()) {
262 for (
auto *
value : initializer_list<TagValue *>{ &m_title, &m_artist, &m_album, &m_year, &m_comment, &m_trackPos, &m_genre }) {
264 switch (
value->dataEncoding()) {
278void Id3v1Tag::readValue(
TagValue &value,
size_t maxLength,
const char *buffer)
280 const char *end = buffer + maxLength - 1;
281 while ((*end == 0x0 || *end ==
' ') && end >= buffer) {
288 if (maxLength >= 3 && BE::toUInt24(buffer) == 0x00EFBBBF) {
298void Id3v1Tag::writeValue(
const TagValue &value,
size_t length,
char *buffer, ostream &targetStream,
Diagnostics &diag)
301 memset(buffer, 0, length);
304 string valueAsString;
306 valueAsString =
value.toString();
307 }
catch (
const ConversionException &) {
309 DiagLevel::Warning,
"Field can not be set because given value can not be converted appropriately.",
"making ID3v1 tag field");
313 auto *valueStart = buffer;
314 auto valueLength = length;
315 auto hasProblematicEncoding =
false;
316 switch (
value.dataEncoding()) {
321 for (
const auto c : valueAsString) {
322 if ((c & 0x80) == 0) {
325 buffer[0] =
static_cast<char>(0xEF);
326 buffer[1] =
static_cast<char>(0xBB);
327 buffer[2] =
static_cast<char>(0xBF);
330 hasProblematicEncoding =
true;
335 hasProblematicEncoding =
true;
337 if (hasProblematicEncoding) {
338 diag.emplace_back(
DiagLevel::Warning,
"The used encoding is unlikely to be supported by other software.",
"making ID3v1 tag field");
342 if (valueAsString.size() > length) {
344 DiagLevel::Warning, argsToString(
"Value has been truncated. Max. ", length,
" characters supported."),
"making ID3v1 tag field");
346 valueAsString.copy(valueStart, valueLength);
348 targetStream.write(buffer,
static_cast<streamsize
>(length));
The Diagnostics class is a container for DiagMessage.
Id3v1Tag()
Constructs a new tag.
void make(std::ostream &targetStream, Diagnostics &diag)
Writes tag information to the specified stream.
void ensureTextValuesAreProperlyEncoded() override
Ensures the encoding of all assigned text values is supported by the tag by converting the character ...
std::size_t fieldCount() const override
Returns the number of present fields.
bool canEncodingBeUsed(TagTextEncoding encoding) const override
Returns only true for TagTextEncoding::Latin1.
bool hasField(KnownField field) const override
Returns an indication whether the specified field is present.
const TagValue & value(KnownField value) const override
Returns the value of the specified field.
bool supportsField(KnownField field) const override
Returns an indication whether the specified field is supported by the tag.
void removeAllFields() override
Removes all fields from the tag.
bool setValueConsideringTypeInfo(KnownField field, const TagValue &value, const std::string &typeInfo)
static constexpr std::string_view tagName
TagType type() const override
Returns the type of the tag as TagParser::TagType.
std::string_view typeName() const override
Returns the type name of the tag as C-style string.
bool setValue(KnownField field, const TagValue &value) override
Assigns the given value to the specified field.
void parse(std::istream &sourceStream, Diagnostics &diag)
Parses tag information from the specified stream.
The exception that is thrown when the data to be parsed holds no parsable information (e....
The TagValue class wraps values of different types.
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
Contains all classes and functions of the TagInfo library.
KnownField
Specifies the field.
TagTextEncoding
Specifies the text encoding.
TagType
Specifies the tag type.