4#include "../diagnostics.h"
5#include "../exceptions.h"
7#include <c++utilities/conversion/conversionexception.h>
8#include <c++utilities/conversion/stringbuilder.h>
11#include <initializer_list>
61 CPP_UTILITIES_UNUSED(diag)
63 stream.read(buffer, 128);
64 if (buffer[0] != 0x54 || buffer[1] != 0x41 || buffer[2] != 0x47) {
68 readValue(m_title, 30, buffer + 3);
69 readValue(m_artist, 30, buffer + 33);
70 readValue(m_album, 30, buffer + 63);
71 readValue(m_year, 4, buffer + 93);
72 const auto is11 = buffer[125] == 0;
74 readValue(m_comment, 28, buffer + 97);
77 readValue(m_comment, 30, buffer + 97);
80 readValue(m_comment, is11 ? 28 : 30, buffer + 97);
96 static const string context(
"making ID3v1 tag");
101 stream.write(buffer, 3);
104 writeValue(m_title, 30, buffer, stream, diag);
105 writeValue(m_artist, 30, buffer, stream, diag);
106 writeValue(m_album, 30, buffer, stream, diag);
107 writeValue(m_year, 4, buffer, stream, diag);
108 writeValue(m_comment, 28, buffer, stream, diag);
119 if (position < 0x00 || position > 0xFF) {
120 throw ConversionException();
122 buffer[1] =
static_cast<char>(position);
123 }
catch (
const ConversionException &) {
125 DiagLevel::Warning,
"Track position field can not be set because given value can not be converted appropriately.", context);
132 if (genreIndex < 0x00 || genreIndex > 0xFF) {
133 throw ConversionException();
135 buffer[2] =
static_cast<char>(genreIndex);
136 }
catch (
const ConversionException &) {
138 "Genre field can not be set because given value can not be converted to a standard genre number supported by ID3v1.", context);
141 stream.write(buffer, 3);
236 auto count = std::size_t(0);
237 for (
const auto &
value : std::initializer_list<const TagValue *>{ &m_title, &m_artist, &m_album, &m_year, &m_comment, &m_trackPos, &m_genre }) {
263 for (
auto *
value : initializer_list<TagValue *>{ &m_title, &m_artist, &m_album, &m_year, &m_comment, &m_trackPos, &m_genre }) {
279void Id3v1Tag::readValue(
TagValue &value,
size_t maxLength,
const char *buffer)
281 const char *end = buffer + maxLength - 1;
282 while ((*end == 0x0 || *end ==
' ') && end >= buffer) {
289 if (maxLength >= 3 && BE::toUInt24(buffer) == 0x00EFBBBF) {
299void Id3v1Tag::writeValue(
const TagValue &value,
size_t length,
char *buffer, ostream &targetStream, Diagnostics &diag)
302 memset(buffer, 0, length);
305 string valueAsString;
308 }
catch (
const ConversionException &) {
310 DiagLevel::Warning,
"Field can not be set because given value can not be converted appropriately.",
"making ID3v1 tag field");
314 auto *valueStart = buffer;
315 auto valueLength = length;
316 auto hasProblematicEncoding =
false;
322 for (
const auto c : valueAsString) {
323 if ((c & 0x80) == 0) {
326 buffer[0] =
static_cast<char>(0xEF);
327 buffer[1] =
static_cast<char>(0xBB);
328 buffer[2] =
static_cast<char>(0xBF);
331 hasProblematicEncoding =
true;
336 hasProblematicEncoding =
true;
338 if (hasProblematicEncoding) {
339 diag.emplace_back(
DiagLevel::Warning,
"The used encoding is unlikely to be supported by other software.",
"making ID3v1 tag field");
343 if (valueAsString.size() > length) {
345 DiagLevel::Warning, argsToString(
"Value has been truncated. Max. ", length,
" characters supported."),
"making ID3v1 tag field");
347 valueAsString.copy(valueStart, valueLength);
349 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 PositionInSet class describes the position of an element in a set which consists of a certain num...
constexpr std::int32_t position() const
Returns the element position of the current instance.
The TagValue class wraps values of different types.
TagTextEncoding dataEncoding() const
Returns the data encoding.
void assignPosition(PositionInSet value)
Assigns the given PositionInSet value.
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
PositionInSet toPositionInSet() const
Converts the value of the current TagValue object to its equivalent PositionInSet representation.
void clearDataAndMetadata()
Wipes assigned data including meta data.
void convertDataEncoding(TagTextEncoding encoding)
Converts the currently assigned text value to the specified encoding.
void assignStandardGenreIndex(int index)
Assigns the given standard genre index to be assigned.
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
bool isEmpty() const
Returns whether no or an empty value is assigned.
int toStandardGenreIndex() const
Converts the value of the current TagValue object to its equivalent standard genre index.
Contains all classes and functions of the TagInfo library.
KnownField
Specifies the field.
TagTextEncoding
Specifies the text encoding.
TagType
Specifies the tag type.