4 #include "../flac/flacmetadata.h"
6 #include "../ogg/oggiterator.h"
8 #include "../id3/id3v2frame.h"
10 #include "../diagnostics.h"
11 #include "../exceptions.h"
13 #include <c++utilities/conversion/binaryconversion.h>
14 #include <c++utilities/conversion/stringbuilder.h>
15 #include <c++utilities/conversion/stringconversion.h>
16 #include <c++utilities/io/binaryreader.h>
17 #include <c++utilities/io/binarywriter.h>
35 VorbisCommentField::VorbisCommentField()
42 VorbisCommentField::VorbisCommentField(
const IdentifierType &
id,
const TagValue &value)
50 template <
class StreamType>
void VorbisCommentField::internalParse(StreamType &stream, std::uint64_t &maxSize,
Diagnostics &diag)
52 static const string context(
"parsing Vorbis comment field");
61 if (
const auto size = LE::toUInt32(buff)) {
62 if (size <= maxSize) {
65 auto data = make_unique<char[]>(size);
66 stream.read(data.get(), size);
67 std::uint32_t idSize = 0;
68 for (
const char *i = data.get(), *end = data.get() + size; i != end && *i !=
'='; ++i, ++idSize)
71 setId(
string(data.get(), idSize));
75 throw InvalidDataException();
79 auto decoded = decodeBase64(data.get() + idSize + 1, size - idSize - 1);
80 stringstream bufferStream(ios_base::in | ios_base::out | ios_base::binary);
81 bufferStream.exceptions(ios_base::failbit | ios_base::badbit);
82 bufferStream.rdbuf()->pubsetbuf(
reinterpret_cast<char *
>(decoded.first.get()), decoded.second);
83 FlacMetaDataBlockPicture pictureBlock(
value());
84 pictureBlock.parse(bufferStream, decoded.second);
86 }
catch (
const TruncatedDataException &) {
89 }
catch (
const ConversionException &) {
90 diag.emplace_back(
DiagLevel::Critical,
"Base64 coding of METADATA_BLOCK_PICTURE is invalid.", context);
91 throw InvalidDataException();
92 }
catch (
const std::ios_base::failure &failure) {
94 argsToString(
"An IO error occurred when reading the METADATA_BLOCK_PICTURE struct: ", failure.what()), context);
97 }
else if (
id().size() + 1 < size) {
103 throw TruncatedDataException();
121 internalParse(iterator, maxSize, diag);
136 internalParse(iterator, maxSize, diag);
151 internalParse(stream, maxSize, diag);
165 static const string context(
"making Vorbis comment field");
178 diag.emplace_back(
DiagLevel::Critical,
"Assigned value of cover field is not picture data.", context);
186 auto buffer = make_unique<char[]>(requiredSize);
187 stringstream bufferStream(ios_base::in | ios_base::out | ios_base::binary);
188 bufferStream.exceptions(ios_base::failbit | ios_base::badbit);
189 bufferStream.rdbuf()->pubsetbuf(buffer.get(), requiredSize);
191 pictureBlock.
make(bufferStream);
192 valueString = encodeBase64(
reinterpret_cast<std::uint8_t *
>(buffer.get()), requiredSize);
194 diag.emplace_back(
DiagLevel::Critical,
"Unable to make METADATA_BLOCK_PICTURE struct from the assigned value.", context);
196 }
catch (
const std::ios_base::failure &failure) {
198 argsToString(
"An IO error occurred when writing the METADATA_BLOCK_PICTURE struct: ", failure.what()), context);
205 const auto size(valueString.size() +
id().size() + 1);
206 if (size > numeric_limits<std::uint32_t>::max()) {
207 diag.emplace_back(
DiagLevel::Critical,
"Assigned value exceeds the maximum size.", context);
210 writer.writeUInt32LE(
static_cast<std::uint32_t
>(size));
211 writer.writeString(
id());
212 writer.writeChar(
'=');
213 writer.writeString(valueString);
214 }
catch (
const ConversionException &) {
215 diag.emplace_back(
DiagLevel::Critical,
"Assigned value can not be converted appropriately.", context);