11#include <c++utilities/conversion/binaryconversion.h>
12#include <c++utilities/conversion/stringbuilder.h>
13#include <c++utilities/conversion/stringconversion.h>
14#include <c++utilities/io/binaryreader.h>
15#include <c++utilities/io/binarywriter.h>
48template <
class StreamType>
void VorbisCommentField::internalParse(StreamType &stream, std::uint64_t &maxSize,
Diagnostics &diag)
50 static const string context(
"parsing Vorbis comment field");
53 diag.emplace_back(
DiagLevel::Critical, argsToString(
"Field expected at ",
static_cast<std::streamoff
>(stream.tellg()),
'.'), context);
59 if (
const auto size = LE::toUInt32(buff)) {
60 if (size <= maxSize) {
63 auto data = make_unique<char[]>(size);
64 stream.read(data.get(), size);
65 std::uint32_t idSize = 0;
66 for (
const char *i = data.get(), *end = data.get() + size; i != end && *i !=
'='; ++i, ++idSize)
69 setId(
string(data.get(), idSize));
73 DiagLevel::Critical, argsToString(
"The field ID at ",
static_cast<std::streamoff
>(stream.tellg()),
" is empty."), context);
74 throw InvalidDataException();
78 auto decoded = decodeBase64(data.get() + idSize + 1, size - idSize - 1);
79 stringstream bufferStream(ios_base::in | ios_base::out | ios_base::binary);
80 bufferStream.exceptions(ios_base::failbit | ios_base::badbit);
81#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
82 bufferStream.rdbuf()->pubsetbuf(
reinterpret_cast<char *
>(decoded.first.get()), decoded.second);
84 bufferStream.write(
reinterpret_cast<const char *
>(decoded.first.get()), decoded.second);
86 FlacMetaDataBlockPicture pictureBlock(
value());
87 pictureBlock.parse(bufferStream, decoded.second);
89 }
catch (
const TruncatedDataException &) {
92 }
catch (
const ConversionException &) {
93 diag.emplace_back(
DiagLevel::Critical,
"Base64 coding of METADATA_BLOCK_PICTURE is invalid.", context);
94 throw InvalidDataException();
95 }
catch (
const std::ios_base::failure &failure) {
97 argsToString(
"An IO error occurred when reading the METADATA_BLOCK_PICTURE struct: ", failure.what()), context);
100 }
else if (
id().size() + 1 < size) {
101 const auto str = std::string_view(data.get() + idSize + 1, size - idSize - 1);
106 }
catch (
const ConversionException &) {
109 diag.emplace_back(
DiagLevel::Warning, argsToString(
"The rating is not a number."), context);
117 diag.emplace_back(
DiagLevel::Critical, argsToString(
"Field at ",
static_cast<std::streamoff
>(stream.tellg()),
" is truncated."), context);
118 throw TruncatedDataException();
136 internalParse(iterator, maxSize, diag);
151 internalParse(iterator, maxSize, diag);
166 internalParse(stream, maxSize, diag);
180 static const string context(
"making Vorbis comment field");
193 diag.emplace_back(
DiagLevel::Critical,
"Assigned value of cover field is not picture data.", context);
201 auto buffer = make_unique<char[]>(requiredSize);
202 stringstream bufferStream(ios_base::in | ios_base::out | ios_base::binary);
203 bufferStream.exceptions(ios_base::failbit | ios_base::badbit);
204#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
205 bufferStream.rdbuf()->pubsetbuf(buffer.get(), requiredSize);
207 pictureBlock.
make(bufferStream);
208#if !(defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION))
209 bufferStream.read(buffer.get(),
static_cast<std::streamsize
>(requiredSize));
211 valueString = encodeBase64(
reinterpret_cast<std::uint8_t *
>(buffer.get()), requiredSize);
214 diag.emplace_back(
DiagLevel::Critical,
"Unable to make METADATA_BLOCK_PICTURE struct from the assigned value.", context);
216 }
catch (
const std::ios_base::failure &failure) {
218 argsToString(
"An IO error occurred when writing the METADATA_BLOCK_PICTURE struct: ", failure.what()), context);
227 const auto size(valueString.size() +
id().size() + 1);
228 if (size > numeric_limits<std::uint32_t>::max()) {
229 diag.emplace_back(
DiagLevel::Critical,
"Assigned value exceeds the maximum size.", context);
232 writer.writeUInt32LE(
static_cast<std::uint32_t
>(size));
233 writer.writeString(
id());
234 writer.writeChar(
'=');
235 writer.writeString(valueString);
236 }
catch (
const ConversionException &) {
237 diag.emplace_back(
DiagLevel::Critical,
"Assigned value can not be converted appropriately.", context);
The Diagnostics class is a container for DiagMessage.
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
The exception that is thrown when the data to be parsed or to be made seems invalid and therefore can...
The OggIterator class helps iterating through all segments of an Ogg bitstream.
std::uint64_t currentCharacterOffset() const
Returns the offset of the current character in the input stream if the iterator is valid; otherwise a...
std::uint64_t streamSize() const
Returns the stream size (which has been specified when constructing the iterator).
The TagField class is used by FieldMapBasedTag to store the fields.
void setTypeInfo(const TypeInfoType &typeInfo)
const TypeInfoType & typeInfo() const
void setId(const IdentifierType &id)
The TagValue class wraps values of different types.
void assignText(const char *text, std::size_t textSize, TagTextEncoding textEncoding=TagTextEncoding::Latin1, TagTextEncoding convertTo=TagTextEncoding::Unspecified)
Assigns a copy of the given text.
void assignPopularity(const Popularity &value)
Assigns the specified popularity value.
Popularity toScaledPopularity(TagType scale=TagType::Unspecified) const
Converts the value of the current TagValue object to its equivalent Popularity representation using t...
std::string toString(TagTextEncoding encoding=TagTextEncoding::Unspecified) const
Converts the value of the current TagValue object to its equivalent std::string representation.
The exception that is thrown when the data to be parsed is truncated and therefore can not be parsed ...
Contains all classes and functions of the TagInfo library.
VorbisCommentFlags
The VorbisCommentFlags enum specifies flags which controls parsing and making of Vorbis comments.
std::string toString() const
Returns the popularity as string in the format "rating" if only a rating is present or in the format ...