8#include <c++utilities/io/binarywriter.h>
49 string context(
"parsing Matroska tag field");
50 simpleTagElement.
parse(diag);
51 bool tagDefaultFound =
false, tagLanguageFound =
false, tagLanguageIETFFound =
false;
56 diag.emplace_back(
DiagLevel::Critical,
"Unable to parse children of \"SimpleTag\"-element.", context);
59 switch (child->id()) {
62 setId(child->readString());
63 context =
"parsing Matroska tag field " +
id();
66 "\"SimpleTag\"-element contains multiple \"TagName\"-elements. Surplus TagName elements will be ignored.", context);
71 if (
value().isEmpty()) {
72 unique_ptr<char[]> buffer = make_unique<char[]>(child->dataSize());
73 child->stream().seekg(
static_cast<streamoff
>(child->dataOffset()));
74 child->stream().read(buffer.get(),
static_cast<streamoff
>(child->dataSize()));
75 switch (child->id()) {
85 "\"SimpleTag\"-element contains multiple \"TagString\"/\"TagBinary\"-elements. Surplus \"TagName\"/\"TagBinary\"-elements will "
91 if (!tagLanguageFound) {
92 tagLanguageFound =
true;
93 auto language = child->readString();
94 if (language !=
"und") {
99 "\"SimpleTag\"-element contains multiple \"TagLanguage\"-elements. Surplus \"TagLanguage\"-elements will be ignored.", context);
103 if (!tagLanguageIETFFound) {
104 tagLanguageIETFFound =
true;
108 "\"SimpleTag\"-element contains multiple \"TagLanguageIETF\"-elements. Surplus \"TagLanguageIETF\"-elements will be ignored.",
113 if (!tagDefaultFound) {
115 tagDefaultFound =
true;
118 "\"SimpleTag\"-element contains multiple \"TagDefault\" elements. Surplus \"TagDefault\"-elements will be ignored.", context);
122 if (parseNestedFields) {
127 "Nested fields are currently not supported. Nested tags can not be displayed and will be discarded when rewriting the file.",
137 "\"SimpleTag\"-element contains unknown element ", child->idToString(),
" at ", child->startOffset(),
". It will be ignored."),
145 }
catch (
const ConversionException &) {
146 diag.emplace_back(
DiagLevel::Warning, argsToString(
"The rating is not a number."), context);
164 static const string context(
"making Matroska \"SimpleTag\" element.");
167 diag.emplace_back(
DiagLevel::Critical,
"Can not make \"SimpleTag\" element with empty \"TagName\".", context);
172 }
catch (
const ConversionException &) {
173 diag.emplace_back(
DiagLevel::Critical,
"The assigned tag value can not be converted to be written appropriately.", context);
196 if (c >=
'a' && c <=
'z') {
225 }
catch (
const ConversionException &) {
227 "The assigned tag value can not be converted to a string and is treated as binary value (which is likely not what you want since "
228 "official Matroska specifiecation doesn't list any binary fields).",
229 "making Matroska \"SimpleTag\" element.");
234 const auto languageSize = m_language.empty() ? 3 : m_language.size();
237 const auto languageIETFElementSize
244 + m_field.id().size()
246 + languageElementSize
247 + languageIETFElementSize
256 m_nestedMaker.emplace_back(nestedField.prepareMaking(diag));
257 m_simpleTagSize += m_nestedMaker.back().m_totalSize;
271 BinaryWriter writer(&stream);
276 stream.write(buff, sizeDenotationLen);
280 stream.write(buff, sizeDenotationLen);
281 stream.write(m_field.id().c_str(),
static_cast<std::streamsize
>(m_field.id().size()));
284 if (m_language.empty()) {
285 stream.put(
static_cast<ostream::char_type
>(0x80 | 3));
286 stream.write(
"und", 3);
289 stream.write(buff, sizeDenotationLen);
290 stream.write(m_language.data(),
static_cast<std::streamsize
>(m_language.size()));
293 if (!m_languageIETF.empty()) {
296 stream.write(buff, sizeDenotationLen);
297 stream.write(m_languageIETF.data(),
static_cast<std::streamsize
>(m_languageIETF.size()));
301 stream.put(
static_cast<ostream::char_type
>(0x80 | 1));
302 stream.put(m_field.isDefault() ? 1 : 0);
307 stream.write(buff, sizeDenotationLen);
308 stream.write(m_field.value().dataPointer(),
static_cast<std::streamsize
>(m_field.value().dataSize()));
312 stream.write(buff, sizeDenotationLen);
313 stream.write(m_stringValue.data(),
static_cast<std::streamsize
>(m_stringValue.size()));
316 for (
const auto &maker : m_nestedMaker) {
The Diagnostics class is a container for DiagMessage.
The EbmlElement class helps to parse EBML files such as Matroska files.
static std::uint8_t calculateSizeDenotationLength(std::uint64_t size)
Returns the length of the size denotation for the specified size in byte.
static std::uint8_t makeSizeDenotation(std::uint64_t size, char *buff)
Makes the size denotation for the specified size and stores it to buff.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
ImplementationType * nextSibling()
Returns the next sibling of the element.
ImplementationType * firstChild()
Returns the first child of the element.
void parse(Diagnostics &diag)
Parses the header information of the element which is read from the related stream at the start offse...
InvalidDataException() noexcept
Constructs a new exception.
The MatroskaTagFieldMaker class helps making tag fields.
void make(std::ostream &stream) const
Saves the field (specified when constructing the object) to the specified stream (makes a "SimpleTag"...
The MatroskaTagField class is used by MatroskaTag to store the fields.
static void normalizeId(std::string &id)
Ensures the specified id is upper-case as recommended by the Matroska spec.
void reparse(EbmlElement &simpleTagElement, Diagnostics &diag, bool parseNestedFields=true)
Parses field information from the specified EbmlElement.
MatroskaTagFieldMaker prepareMaking(Diagnostics &diag)
Prepares making.
void make(std::ostream &stream, Diagnostics &diag)
Saves the field to the specified stream (makes a "SimpleTag" element).
MatroskaTagField()
Constructs a new MatroskaTagField.
void setDefault(bool isDefault)
const std::vector< MatroskaTagField > & nestedFields() const
void setId(const IdentifierType &id)
The TagValue class wraps values of different types.
void assignData(const char *data, std::size_t length, TagDataType type=TagDataType::Binary, TagTextEncoding encoding=TagTextEncoding::Latin1)
void assignPopularity(const Popularity &value)
Assigns the specified popularity value.
const Locale & locale() const
Returns the locale.
constexpr TAG_PARSER_EXPORT std::string_view rating()
Contains all classes and functions of the TagInfo library.
LocaleFormat
The LocaleFormat enum class specifies the format used by a LocaleDetail.
The Popularity class contains a value for ID3v2's "Popularimeter" field.