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);
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);
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);
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...
Failure() noexcept
Constructs a new exception.
InvalidDataException() noexcept
Constructs a new exception.
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).
void setTypeInfo(const TypeInfoType &typeInfo)
typename TagFieldTraits< VorbisCommentField >::IdentifierType IdentifierType
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.
TruncatedDataException() noexcept
Constructs a new exception.
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 ...