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 },
109 {
year(), KnownField::RecordDate },
127 const auto knownField(fieldMap.find(
id));
128 return knownField != fieldMap.cend() ? knownField->second : KnownField::Invalid;
134 template <
class StreamType>
void VorbisComment::internalParse(StreamType &stream, std::uint64_t maxSize,
VorbisCommentFlags flags,
Diagnostics &diag)
137 static const string context(
"parsing Vorbis comment");
138 std::uint64_t startOffset =
static_cast<std::uint64_t
>(stream.tellg());
142 bool skipSignature = flags & VorbisCommentFlags::NoSignature;
143 if (!skipSignature) {
146 skipSignature = (BE::toUInt64(sig) & 0xffffffffffffff00u) == 0x03766F7262697300u;
153 const auto vendorSize = LE::toUInt32(sig);
154 if (vendorSize <= maxSize) {
155 auto buff = make_unique<char[]>(vendorSize);
156 stream.read(buff.get(), vendorSize);
160 diag.emplace_back(DiagLevel::Critical,
"Vendor information is truncated.", context);
161 throw TruncatedDataException();
163 maxSize -= vendorSize;
168 std::uint32_t fieldCount = LE::toUInt32(sig);
169 for (std::uint32_t i = 0; i < fieldCount; ++i) {
171 VorbisCommentField field;
173 field.parse(stream, maxSize, diag);
174 fields().emplace(field.id(), move(field));
175 }
catch (
const TruncatedDataException &) {
177 }
catch (
const Failure &) {
181 if (!(flags & VorbisCommentFlags::NoFramingByte)) {
184 m_size =
static_cast<std::uint32_t
>(
static_cast<std::uint64_t
>(stream.tellg()) - startOffset);
190 for (
auto i = first; i != end; ++i) {
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(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)) {