4 #include "../vorbis/vorbiscomment.h"
6 #include "../exceptions.h"
7 #include "../mediafileinfo.h"
8 #include "../mediaformat.h"
10 #include "resources/config.h"
12 #include <c++utilities/io/copy.h>
31 FlacStream::FlacStream(
MediaFileInfo &mediaFileInfo, std::uint64_t startOffset)
33 , m_mediaFileInfo(mediaFileInfo)
46 if (!m_vorbisComment) {
47 m_vorbisComment = make_unique<VorbisComment>();
49 return m_vorbisComment.get();
58 if (!m_vorbisComment) {
61 m_vorbisComment.reset();
67 static const string context(
"parsing raw FLAC header");
76 if (
m_reader.readUInt32BE() != 0x664C6143) {
86 header.parseHeader(buffer);
92 switch (static_cast<FlacMetaDataBlockType>(header.type())) {
94 if (header.dataSize() >= 0x22) {
97 streamInfo.
parse(buffer);
104 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_STREAMINFO\" is truncated and will be ignored.", context);
111 if (!m_vorbisComment) {
112 m_vorbisComment = make_unique<VorbisComment>();
131 diag.emplace_back(
DiagLevel::Warning,
"\"METADATA_BLOCK_PICTURE\" contains no picture.", context);
134 if (!m_vorbisComment) {
136 m_vorbisComment = make_unique<VorbisComment>();
139 m_vorbisComment->fields().insert(make_pair(coverField.
id(), move(coverField)));
143 diag.emplace_back(
DiagLevel::Critical,
"\"METADATA_BLOCK_PICTURE\" is truncated and will be ignored.", context);
148 m_paddingSize += 4 + header.dataSize();
160 m_streamOffset = static_cast<std::uint32_t>(
m_istream->tellg());
176 istream &originalStream = m_mediaFileInfo.
stream();
177 originalStream.seekg(static_cast<streamoff>(
m_startOffset + 4));
181 BE::getBytes(static_cast<std::uint32_t>(0x664C6143u), copy.buffer());
184 std::streamoff lastStartOffset = -1;
191 originalStream.read(copy.buffer(), 4);
195 switch (static_cast<FlacMetaDataBlockType>(header.
type())) {
200 originalStream.seekg(header.
dataSize(), ios_base::cur);
204 originalStream.seekg(-4, ios_base::cur);
207 lastActuallyWrittenHeader = header;
209 }
while (!header.
isLast());
212 if (lastStartOffset >= 4
213 && ((!m_vorbisComment && !lastActuallyWrittenHeader.
isLast()) || (m_vorbisComment && lastActuallyWrittenHeader.
isLast()))) {
215 lastActuallyWrittenHeader.
setLast(!m_vorbisComment);
217 originalStream.seekg(lastActuallyWrittenHeader.
dataSize(), ios_base::cur);
221 if (!m_vorbisComment) {
222 return lastStartOffset >= 0 ? lastStartOffset : 0;
237 auto dataSize(static_cast<std::uint64_t>(endOffset) - static_cast<std::uint64_t>(lastStartOffset) - 4);
238 if (dataSize > 0xFFFFFF) {
240 diag.emplace_back(
DiagLevel::Critical,
"Vorbis Comment is too big and will be truncated.",
"write Vorbis Comment to FLAC stream");
242 header.
setDataSize(static_cast<std::uint32_t>(dataSize));
243 header.
setLast(!m_vorbisComment->hasField(coverId));
246 outputStream.seekp(static_cast<streamoff>(dataSize), ios_base::cur);
247 lastActuallyWrittenHeader = header;
251 return lastStartOffset;
254 const auto coverFields = m_vorbisComment->fields().equal_range(coverId);
255 for (
auto i = coverFields.first; i != coverFields.second;) {
263 header.
setLast(++i == coverFields.second);
268 lastStartOffset = lastCoverStartOffset;
269 lastActuallyWrittenHeader = header;
274 diag.emplace_back(
DiagLevel::Critical,
"Unable to serialize \"METADATA_BLOCK_PICTURE\" from assigned value.",
275 "write \"METADATA_BLOCK_PICTURE\" to FLAC stream");
282 if (!lastActuallyWrittenHeader.
isLast()) {
284 lastActuallyWrittenHeader.
setLast(
true);
289 return lastStartOffset;
298 CPP_UTILITIES_UNUSED(diag)