4 #include "../ogg/oggiterator.h"
6 #include "../diagnostics.h"
7 #include "../exceptions.h"
9 #include <c++utilities/io/binaryreader.h>
10 #include <c++utilities/io/binarywriter.h>
11 #include <c++utilities/io/copy.h>
29 case KnownField::Vendor:
39 case KnownField::Vendor:
49 using namespace VorbisCommentIds;
52 return std::string(
album());
54 return std::string(
artist());
58 return std::string(
cover());
59 case KnownField::RecordDate:
60 return std::string(
date());
62 return std::string(
title());
64 return std::string(
genre());
69 case KnownField::PartNumber:
75 case KnownField::EncoderSettings:
82 return std::string(
label());
85 case KnownField::Language:
90 return std::string(
lyrics());
98 KnownField VorbisComment::internallyGetKnownField(
const IdentifierType &
id)
const
100 using namespace VorbisCommentIds;
102 static const std::map<std::string_view, KnownField, CaseInsensitiveStringComparer> fieldMap({
107 {
date(), KnownField::RecordDate },
108 {
year(), KnownField::RecordDate },
126 const auto knownField(fieldMap.find(
id));
127 return knownField != fieldMap.cend() ? knownField->second : KnownField::Invalid;
133 template <
class StreamType>
void VorbisComment::internalParse(StreamType &stream, std::uint64_t maxSize,
VorbisCommentFlags flags,
Diagnostics &diag)
136 static const string context(
"parsing Vorbis comment");
137 std::uint64_t startOffset =
static_cast<std::uint64_t
>(stream.tellg());
141 bool skipSignature = flags & VorbisCommentFlags::NoSignature;
142 if (!skipSignature) {
145 skipSignature = (BE::toUInt64(sig) & 0xffffffffffffff00u) == 0x03766F7262697300u;
152 const auto vendorSize = LE::toUInt32(sig);
153 if (vendorSize <= maxSize) {
154 auto buff = make_unique<char[]>(vendorSize);
155 stream.read(buff.get(), vendorSize);
159 diag.emplace_back(DiagLevel::Critical,
"Vendor information is truncated.", context);
160 throw TruncatedDataException();
162 maxSize -= vendorSize;
167 std::uint32_t fieldCount = LE::toUInt32(sig);
168 for (std::uint32_t i = 0; i < fieldCount; ++i) {
170 VorbisCommentField field;
172 field.parse(stream, maxSize, diag);
173 fields().emplace(field.id(), move(field));
174 }
catch (
const TruncatedDataException &) {
176 }
catch (
const Failure &) {
180 if (!(flags & VorbisCommentFlags::NoFramingByte)) {
183 m_size =
static_cast<std::uint32_t
>(
static_cast<std::uint64_t
>(stream.tellg()) - startOffset);
188 if (fields().find(dateFieldId) == fields().end()) {
189 const auto [first, end] = fields().equal_range(yearFieldId);
190 for (
auto i = first; i != end; ++i) {
191 fields().emplace(dateFieldId, std::move(i->second));
193 fields().erase(first, end);
196 diag.emplace_back(DiagLevel::Critical,
"Signature is invalid.", context);
197 throw InvalidDataException();
199 }
catch (
const TruncatedDataException &) {
200 m_size =
static_cast<std::uint32_t
>(
static_cast<std::uint64_t
>(stream.tellg()) - startOffset);
201 diag.emplace_back(DiagLevel::Critical,
"Vorbis comment is truncated.", context);
215 internalParse(iterator, iterator.
streamSize(), flags, diag);
227 internalParse(stream, maxSize, flags, diag);
240 static const string context(
"making Vorbis comment");
243 m_vendor.toString(vendor);
244 }
catch (
const ConversionException &) {
245 diag.emplace_back(DiagLevel::Warning,
"Can not convert the assigned vendor to string.", context);
247 BinaryWriter writer(&stream);
248 if (!(flags & VorbisCommentFlags::NoSignature)) {
250 static const char sig[7] = { 0x03, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
251 stream.write(sig,
sizeof(sig));
254 writer.writeUInt32LE(
static_cast<std::uint32_t
>(vendor.size()));
255 writer.writeString(vendor);
257 const auto fieldCountOffset = stream.tellp();
258 writer.writeUInt32LE(0);
260 std::uint32_t fieldsWritten = 0;
261 for (
auto i : fields()) {
265 if (field.
make(writer, flags, diag)) {
273 const auto framingByteOffset = stream.tellp();
274 stream.seekp(fieldCountOffset);
275 writer.writeUInt32LE(fieldsWritten);
276 stream.seekp(framingByteOffset);
278 if (!(flags & VorbisCommentFlags::NoFramingByte)) {
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 FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
typename FieldMapBasedTagTraits< VorbisComment >::FieldType::IdentifierType IdentifierType
The OggIterator class helps iterating through all segments of an OGG bitstream.
std::uint64_t streamSize() const
Returns the stream size (which has been specified when constructing the iterator).
TagValue & value()
Returns the value of the current TagField.
The TagValue class wraps values of different types.
bool isEmpty() const
Returns whether no or an empty value is assigned.
#define CHECK_MAX_SIZE(sizeDenotation)
Throws TruncatedDataException() if the specified sizeDenotation exceeds maxSize; otherwise maxSize is...
constexpr TAG_PARSER_EXPORT std::string_view album()
constexpr TAG_PARSER_EXPORT std::string_view encoderSettings()
constexpr TAG_PARSER_EXPORT std::string_view description()
constexpr TAG_PARSER_EXPORT std::string_view title()
constexpr TAG_PARSER_EXPORT std::string_view comment()
constexpr TAG_PARSER_EXPORT std::string_view language()
constexpr TAG_PARSER_EXPORT std::string_view composer()
constexpr TAG_PARSER_EXPORT std::string_view partNumber()
constexpr TAG_PARSER_EXPORT std::string_view genre()
constexpr TAG_PARSER_EXPORT std::string_view artist()
constexpr TAG_PARSER_EXPORT std::string_view lyrics()
constexpr TAG_PARSER_EXPORT std::string_view encoder()
constexpr TAG_PARSER_EXPORT std::string_view lyricist()
Contains all classes and functions of the TagInfo library.
KnownField
Specifies the field.
VorbisCommentFlags
The VorbisCommentFlags enum specifies flags which controls parsing and making of Vorbis comments.