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;
69 case KnownField::PartNumber:
75 case KnownField::EncoderSettings:
85 case KnownField::Language:
98 KnownField VorbisComment::internallyGetKnownField(
const IdentifierType &
id)
const
100 using namespace VorbisCommentIds;
102 static const map<string, KnownField, CaseInsensitiveStringComparer> fieldMap({
125 const auto knownField(fieldMap.find(
id));
126 return knownField != fieldMap.cend() ? knownField->second : KnownField::Invalid;
132 template <
class StreamType>
void VorbisComment::internalParse(StreamType &stream, std::uint64_t maxSize,
VorbisCommentFlags flags,
Diagnostics &diag)
135 static const string context(
"parsing Vorbis comment");
136 std::uint64_t startOffset =
static_cast<std::uint64_t
>(stream.tellg());
140 bool skipSignature = flags & VorbisCommentFlags::NoSignature;
141 if (!skipSignature) {
144 skipSignature = (BE::toUInt64(sig) & 0xffffffffffffff00u) == 0x03766F7262697300u;
151 const auto vendorSize = LE::toUInt32(sig);
152 if (vendorSize <= maxSize) {
153 auto buff = make_unique<char[]>(vendorSize);
154 stream.read(buff.get(), vendorSize);
158 diag.emplace_back(DiagLevel::Critical,
"Vendor information is truncated.", context);
159 throw TruncatedDataException();
161 maxSize -= vendorSize;
166 std::uint32_t fieldCount = LE::toUInt32(sig);
167 for (std::uint32_t i = 0; i < fieldCount; ++i) {
169 VorbisCommentField field;
171 field.parse(stream, maxSize, diag);
172 fields().emplace(field.id(), move(field));
173 }
catch (
const TruncatedDataException &) {
175 }
catch (
const Failure &) {
179 if (!(flags & VorbisCommentFlags::NoFramingByte)) {
182 m_size =
static_cast<std::uint32_t
>(
static_cast<std::uint64_t
>(stream.tellg()) - startOffset);
184 diag.emplace_back(DiagLevel::Critical,
"Signature is invalid.", context);
185 throw InvalidDataException();
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);
203 internalParse(iterator, iterator.
streamSize(), flags, diag);
215 internalParse(stream, maxSize, flags, diag);
228 static const string context(
"making Vorbis comment");
231 m_vendor.toString(vendor);
232 }
catch (
const ConversionException &) {
233 diag.emplace_back(DiagLevel::Warning,
"Can not convert the assigned vendor to string.", context);
235 BinaryWriter writer(&stream);
236 if (!(flags & VorbisCommentFlags::NoSignature)) {
238 static const char sig[7] = { 0x03, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
239 stream.write(sig,
sizeof(sig));
242 writer.writeUInt32LE(vendor.size());
243 writer.writeString(vendor);
245 const auto fieldCountOffset = stream.tellp();
246 writer.writeUInt32LE(0);
248 std::uint32_t fieldsWritten = 0;
249 for (
auto i : fields()) {
253 if (field.
make(writer, flags, diag)) {
261 const auto framingByteOffset = stream.tellp();
262 stream.seekp(fieldCountOffset);
263 writer.writeUInt32LE(fieldsWritten);
264 stream.seekp(framingByteOffset);
266 if (!(flags & VorbisCommentFlags::NoFramingByte)) {