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;
59 case KnownField::RecordDate:
70 case KnownField::PartNumber:
76 case KnownField::EncoderSettings:
86 case KnownField::Language:
99 KnownField VorbisComment::internallyGetKnownField(
const IdentifierType &
id)
const
101 using namespace VorbisCommentIds;
103 static const map<string, KnownField, CaseInsensitiveStringComparer> fieldMap({
108 {
date(), 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);
185 diag.emplace_back(DiagLevel::Critical,
"Signature is invalid.", context);
186 throw InvalidDataException();
188 }
catch (
const TruncatedDataException &) {
189 m_size =
static_cast<std::uint32_t
>(
static_cast<std::uint64_t
>(stream.tellg()) - startOffset);
190 diag.emplace_back(DiagLevel::Critical,
"Vorbis comment is truncated.", context);
204 internalParse(iterator, iterator.
streamSize(), flags, diag);
216 internalParse(stream, maxSize, flags, diag);
229 static const string context(
"making Vorbis comment");
232 m_vendor.toString(vendor);
233 }
catch (
const ConversionException &) {
234 diag.emplace_back(DiagLevel::Warning,
"Can not convert the assigned vendor to string.", context);
236 BinaryWriter writer(&stream);
237 if (!(flags & VorbisCommentFlags::NoSignature)) {
239 static const char sig[7] = { 0x03, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
240 stream.write(sig,
sizeof(sig));
243 writer.writeUInt32LE(vendor.size());
244 writer.writeString(vendor);
246 const auto fieldCountOffset = stream.tellp();
247 writer.writeUInt32LE(0);
249 std::uint32_t fieldsWritten = 0;
250 for (
auto i : fields()) {
254 if (field.
make(writer, flags, diag)) {
262 const auto framingByteOffset = stream.tellp();
263 stream.seekp(fieldCountOffset);
264 writer.writeUInt32LE(fieldsWritten);
265 stream.seekp(framingByteOffset);
267 if (!(flags & VorbisCommentFlags::NoFramingByte)) {