Tag Parser  9.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
vorbiscomment.cpp
Go to the documentation of this file.
1 #include "./vorbiscomment.h"
2 #include "./vorbiscommentids.h"
3 
4 #include "../ogg/oggiterator.h"
5 
6 #include "../diagnostics.h"
7 #include "../exceptions.h"
8 
9 #include <c++utilities/io/binaryreader.h>
10 #include <c++utilities/io/binarywriter.h>
11 #include <c++utilities/io/copy.h>
12 
13 #include <map>
14 #include <memory>
15 
16 using namespace std;
17 using namespace CppUtilities;
18 
19 namespace TagParser {
20 
26 const TagValue &VorbisComment::value(KnownField field) const
27 {
28  switch (field) {
29  case KnownField::Vendor:
30  return vendor();
31  default:
33  }
34 }
35 
36 bool VorbisComment::setValue(KnownField field, const TagValue &value)
37 {
38  switch (field) {
39  case KnownField::Vendor:
40  setVendor(value);
41  return true;
42  default:
43  return FieldMapBasedTag<VorbisComment>::setValue(field, value);
44  }
45 }
46 
47 VorbisComment::IdentifierType VorbisComment::internallyGetFieldId(KnownField field) const
48 {
49  using namespace VorbisCommentIds;
50  switch (field) {
51  case KnownField::Album:
52  return album();
53  case KnownField::Artist:
54  return artist();
56  return comment();
57  case KnownField::Cover:
58  return cover();
59  case KnownField::Year:
60  return date();
61  case KnownField::Title:
62  return title();
63  case KnownField::Genre:
64  return genre();
66  return trackNumber();
68  return diskNumber();
69  case KnownField::PartNumber:
70  return partNumber();
72  return composer();
74  return encoder();
75  case KnownField::EncoderSettings:
76  return encoderSettings();
78  return description();
80  return grouping();
82  return label();
84  return performer();
85  case KnownField::Language:
86  return language();
88  return lyricist();
89  case KnownField::Lyrics:
90  return lyrics();
92  return albumArtist();
93  default:
94  return string();
95  }
96 }
97 
98 KnownField VorbisComment::internallyGetKnownField(const IdentifierType &id) const
99 {
100  using namespace VorbisCommentIds;
101  // clang-format off
102  static const map<string, KnownField, CaseInsensitiveStringComparer> fieldMap({
103  { album(), KnownField::Album },
104  { artist(), KnownField::Artist },
106  { cover(), KnownField::Cover },
107  { date(), KnownField::Year },
108  { title(), KnownField::Title },
109  { genre(), KnownField::Genre },
112  { partNumber(), KnownField::PartNumber },
115  { encoderSettings(), KnownField::EncoderSettings },
121  { lyrics(), KnownField::Lyrics },
123  });
124  // clang-format on
125  const auto knownField(fieldMap.find(id));
126  return knownField != fieldMap.cend() ? knownField->second : KnownField::Invalid;
127 }
128 
132 template <class StreamType> void VorbisComment::internalParse(StreamType &stream, std::uint64_t maxSize, VorbisCommentFlags flags, Diagnostics &diag)
133 {
134  // prepare parsing
135  static const string context("parsing Vorbis comment");
136  std::uint64_t startOffset = static_cast<std::uint64_t>(stream.tellg());
137  try {
138  // read signature: 0x3 + "vorbis"
139  char sig[8];
140  bool skipSignature = flags & VorbisCommentFlags::NoSignature;
141  if (!skipSignature) {
142  CHECK_MAX_SIZE(7);
143  stream.read(sig, 7);
144  skipSignature = (BE::toUInt64(sig) & 0xffffffffffffff00u) == 0x03766F7262697300u;
145  }
146  if (skipSignature) {
147  // read vendor (length prefixed string)
148  {
149  CHECK_MAX_SIZE(4);
150  stream.read(sig, 4);
151  const auto vendorSize = LE::toUInt32(sig);
152  if (vendorSize <= maxSize) {
153  auto buff = make_unique<char[]>(vendorSize);
154  stream.read(buff.get(), vendorSize);
155  m_vendor.assignData(move(buff), vendorSize, TagDataType::Text, TagTextEncoding::Utf8);
156  // TODO: Is the vendor string actually UTF-8 (like the field values)?
157  } else {
158  diag.emplace_back(DiagLevel::Critical, "Vendor information is truncated.", context);
159  throw TruncatedDataException();
160  }
161  maxSize -= vendorSize;
162  }
163  // read field count
164  CHECK_MAX_SIZE(4);
165  stream.read(sig, 4);
166  std::uint32_t fieldCount = LE::toUInt32(sig);
167  for (std::uint32_t i = 0; i < fieldCount; ++i) {
168  // read fields
169  VorbisCommentField field;
170  try {
171  field.parse(stream, maxSize, diag);
172  fields().emplace(field.id(), move(field));
173  } catch (const TruncatedDataException &) {
174  throw;
175  } catch (const Failure &) {
176  // nothing to do here since notifications will be added anyways
177  }
178  }
179  if (!(flags & VorbisCommentFlags::NoFramingByte)) {
180  stream.ignore(); // skip framing byte
181  }
182  m_size = static_cast<std::uint32_t>(static_cast<std::uint64_t>(stream.tellg()) - startOffset);
183  } else {
184  diag.emplace_back(DiagLevel::Critical, "Signature is invalid.", context);
185  throw InvalidDataException();
186  }
187  } catch (const TruncatedDataException &) {
188  m_size = static_cast<std::uint32_t>(static_cast<std::uint64_t>(stream.tellg()) - startOffset);
189  diag.emplace_back(DiagLevel::Critical, "Vorbis comment is truncated.", context);
190  throw;
191  }
192 }
193 
201 void VorbisComment::parse(OggIterator &iterator, VorbisCommentFlags flags, Diagnostics &diag)
202 {
203  internalParse(iterator, iterator.streamSize(), flags, diag);
204 }
205 
213 void VorbisComment::parse(istream &stream, std::uint64_t maxSize, VorbisCommentFlags flags, Diagnostics &diag)
214 {
215  internalParse(stream, maxSize, flags, diag);
216 }
217 
225 void VorbisComment::make(std::ostream &stream, VorbisCommentFlags flags, Diagnostics &diag)
226 {
227  // prepare making
228  static const string context("making Vorbis comment");
229  string vendor;
230  try {
231  m_vendor.toString(vendor);
232  } catch (const ConversionException &) {
233  diag.emplace_back(DiagLevel::Warning, "Can not convert the assigned vendor to string.", context);
234  }
235  BinaryWriter writer(&stream);
236  if (!(flags & VorbisCommentFlags::NoSignature)) {
237  // write signature
238  static const char sig[7] = { 0x03, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
239  stream.write(sig, sizeof(sig));
240  }
241  // write vendor
242  writer.writeUInt32LE(vendor.size());
243  writer.writeString(vendor);
244  // write field count later
245  const auto fieldCountOffset = stream.tellp();
246  writer.writeUInt32LE(0);
247  // write fields
248  std::uint32_t fieldsWritten = 0;
249  for (auto i : fields()) {
250  VorbisCommentField &field = i.second;
251  if (!field.value().isEmpty()) {
252  try {
253  if (field.make(writer, flags, diag)) {
254  ++fieldsWritten;
255  }
256  } catch (const Failure &) {
257  }
258  }
259  }
260  // write field count
261  const auto framingByteOffset = stream.tellp();
262  stream.seekp(fieldCountOffset);
263  writer.writeUInt32LE(fieldsWritten);
264  stream.seekp(framingByteOffset);
265  // write framing byte
266  if (!(flags & VorbisCommentFlags::NoFramingByte)) {
267  stream.put(0x01);
268  }
269 }
270 
271 } // namespace TagParser
TagParser::Mp4TagAtomIds::Album
Definition: mp4ids.h:86
TagParser::VorbisCommentIds::performer
constexpr const TAG_PARSER_EXPORT char * performer()
Definition: vorbiscommentids.h:65
vorbiscommentids.h
TagParser::RawDataType::Utf8
Definition: mp4tagfield.h:21
TagParser::VorbisCommentFlags
VorbisCommentFlags
The VorbisCommentFlags enum specifies flags which controls parsing and making of Vorbis comments.
Definition: vorbiscommentfield.h:16
TagParser::MatroskaTagIds::title
constexpr const TAG_PARSER_EXPORT char * title()
Definition: matroskatagid.h:39
TagParser::Mp4TagAtomIds::Lyrics
Definition: mp4ids.h:105
TagParser::Mp4TagAtomIds::Encoder
Definition: mp4ids.h:97
CHECK_MAX_SIZE
#define CHECK_MAX_SIZE(sizeDenotation)
Throws TruncatedDataException() if the specified sizeDenotation exceeds maxSize; otherwise maxSize is...
Definition: exceptions.h:70
TagParser::FieldMapBasedTag< VorbisComment >::IdentifierType
typename FieldMapBasedTagTraits< VorbisComment >::FieldType::IdentifierType IdentifierType
Definition: fieldbasedtag.h:36
TagParser::OggIterator
The OggIterator class helps iterating through all segments of an OGG bitstream.
Definition: oggiterator.h:11
vorbiscomment.h
TagParser::Mp4TagAtomIds::Cover
Definition: mp4ids.h:94
TagParser::Mp4TagExtendedNameIds::label
const char * label
Definition: mp4ids.cpp:31
TagParser::OggIterator::streamSize
std::uint64_t streamSize() const
Returns the stream size (which has been specified when constructing the iterator).
Definition: oggiterator.h:114
TagParser::VorbisCommentField::make
bool make(CppUtilities::BinaryWriter &writer, VorbisCommentFlags flags, Diagnostics &diag)
Writes the field to a stream using the specified writer.
Definition: vorbiscommentfield.cpp:163
TagParser::VorbisCommentIds::date
constexpr const TAG_PARSER_EXPORT char * date()
Definition: vorbiscommentids.h:141
TagParser::Diagnostics
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
TagParser::Mp4TagAtomIds::TrackPosition
Definition: mp4ids.h:116
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::MatroskaTagIds::encoderSettings
constexpr const TAG_PARSER_EXPORT char * encoderSettings()
Definition: matroskatagid.h:326
TagParser::VorbisCommentIds::trackNumber
constexpr const TAG_PARSER_EXPORT char * trackNumber()
Definition: vorbiscommentids.h:13
TagParser::MatroskaTagIds::genre
constexpr const TAG_PARSER_EXPORT char * genre()
Definition: matroskatagid.h:214
TagParser::MatroskaTagIds::composer
constexpr const TAG_PARSER_EXPORT char * composer()
Definition: matroskatagid.h:93
TagParser::MatroskaTagIds::lyricist
constexpr const TAG_PARSER_EXPORT char * lyricist()
Definition: matroskatagid.h:105
TagParser::MatroskaTagIds::language
constexpr const TAG_PARSER_EXPORT char * language()
Definition: matroskatagid.h:346
TagParser::MatroskaIds::Title
Definition: matroskaid.h:54
TagParser::Mp4TagAtomIds::AlbumArtist
Definition: mp4ids.h:87
TagParser::VorbisCommentIds::diskNumber
constexpr const TAG_PARSER_EXPORT char * diskNumber()
Definition: vorbiscommentids.h:17
TagParser::Mp4TagAtomIds::Year
Definition: mp4ids.h:122
TagParser::Failure
The class inherits from std::exception and serves as base class for exceptions thrown by the elements...
Definition: exceptions.h:11
TagParser::TagValue::isEmpty
bool isEmpty() const
Returns whether an empty value is assigned.
Definition: tagvalue.h:449
TagParser::TagField::value
TagValue & value()
Returns the value of the current TagField.
Definition: generictagfield.h:144
TagParser::Mp4TagAtomIds::Lyricist
Definition: mp4ids.h:104
TagParser::Mp4TagAtomIds::Description
Definition: mp4ids.h:95
CppUtilities
Definition: abstractcontainer.h:15
TagParser::VorbisCommentIds::grouping
constexpr const TAG_PARSER_EXPORT char * grouping()
Definition: vorbiscommentids.h:45
TagParser::Mp4TagAtomIds::Genre
Definition: mp4ids.h:101
TagParser::MatroskaTagIds::artist
constexpr const TAG_PARSER_EXPORT char * artist()
Definition: matroskatagid.h:77
TagParser::MatroskaTagIds::partNumber
constexpr const TAG_PARSER_EXPORT char * partNumber()
Definition: matroskatagid.h:30
TagParser::KnownField
KnownField
Specifies the field.
Definition: tag.h:42
TagParser::Mp4TagAtomIds::Grouping
Definition: mp4ids.h:102
TagParser::FieldMapBasedTag
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
Definition: fieldbasedtag.h:31
TagParser::MatroskaTagIds::lyrics
constexpr const TAG_PARSER_EXPORT char * lyrics()
Definition: matroskatagid.h:101
TagParser::TagValue
The TagValue class wraps values of different types. It is meant to be assigned to a tag field.
Definition: tagvalue.h:75
TagParser::MatroskaTagIds::comment
constexpr const TAG_PARSER_EXPORT char * comment()
Definition: matroskatagid.h:309
TagParser::VorbisCommentIds::cover
constexpr const TAG_PARSER_EXPORT char * cover()
Definition: vorbiscommentids.h:165
TagParser::VorbisCommentField
The VorbisCommentField class is used by VorbisComment to store the fields.
Definition: vorbiscommentfield.h:47
TagParser::MatroskaTagIds::encoder
constexpr const TAG_PARSER_EXPORT char * encoder()
Definition: matroskatagid.h:322
TagParser::MatroskaTagIds::album
constexpr const TAG_PARSER_EXPORT char * album()
Definition: matroskatagid.h:81
TagParser::VorbisCommentIds::albumArtist
constexpr const TAG_PARSER_EXPORT char * albumArtist()
Definition: vorbiscommentids.h:41
TagParser::Mp4TagAtomIds::Artist
Definition: mp4ids.h:88
TagParser::Mp4TagAtomIds::RecordLabel
Definition: mp4ids.h:114
TagParser::Mp4TagAtomIds::DiskPosition
Definition: mp4ids.h:96
TagParser::Mp4TagAtomIds::Composer
Definition: mp4ids.h:92
TagParser::Mp4TagAtomIds::Comment
Definition: mp4ids.h:91
TagParser::Mp4TagAtomIds::Performers
Definition: mp4ids.h:107
TagParser::MatroskaTagIds::description
constexpr const TAG_PARSER_EXPORT char * description()
Definition: matroskatagid.h:234