Fix warnings, mostly about implicit int conversions
This should fix all non-erros, leaving only warnings which are indeed potential problems. The following warnings should be safe to ignore: * Conversions of various offsets from uint64 to std::streamoff/int64 are safe because such offsets have been obtained via tellg() and other functions returning std::streamoff in the first place. * It also works vice-versa since tellg() should not return negative offsets with exceptions enabled. * Conversions from char to unsigned char are also ok. * Unused diag arguments can be ignored (those might be useful later). * Annotate all intended fallthoughs.
This commit is contained in:
parent
404e4f751f
commit
0a640c9f7f
|
@ -211,7 +211,7 @@ string AbstractTrack::description() const
|
|||
void AbstractTrack::parseHeader(Diagnostics &diag)
|
||||
{
|
||||
m_headerValid = false;
|
||||
m_istream->seekg(m_startOffset, ios_base::beg);
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||
try {
|
||||
internalParseHeader(diag);
|
||||
m_headerValid = true;
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace TagParser {
|
|||
|
||||
void AdtsStream::internalParseHeader(Diagnostics &diag)
|
||||
{
|
||||
VAR_UNUSED(diag)
|
||||
|
||||
//static const string context("parsing ADTS frame header");
|
||||
if (!m_istream) {
|
||||
throw NoDataFoundException();
|
||||
|
@ -28,7 +30,7 @@ void AdtsStream::internalParseHeader(Diagnostics &diag)
|
|||
} else {
|
||||
m_size = static_cast<uint64>(m_istream->tellg()) + 125u - m_startOffset;
|
||||
}
|
||||
m_istream->seekg(m_startOffset, ios_base::beg);
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||
// parse frame header
|
||||
m_firstFrame.parseHeader(m_reader);
|
||||
m_format = Mpeg4AudioObjectIds::idToMediaFormat(m_firstFrame.mpeg4AudioObjectId());
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <c++utilities/io/binaryreader.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
using namespace IoUtilities;
|
||||
|
||||
|
@ -42,7 +44,7 @@ void AvcConfiguration::parse(BinaryReader &reader, uint64 maxSize)
|
|||
}
|
||||
spsInfos.emplace_back();
|
||||
try {
|
||||
spsInfos.back().parse(reader, maxSize);
|
||||
spsInfos.back().parse(reader, maxSize > numeric_limits<uint32>::max() ? numeric_limits<uint32>::max() : static_cast<uint32>(maxSize));
|
||||
} catch (const TruncatedDataException &) {
|
||||
// TODO: log parsing error
|
||||
if (spsInfos.back().size > maxSize - 2) {
|
||||
|
@ -65,7 +67,7 @@ void AvcConfiguration::parse(BinaryReader &reader, uint64 maxSize)
|
|||
}
|
||||
ppsInfos.emplace_back();
|
||||
try {
|
||||
ppsInfos.back().parse(reader, maxSize);
|
||||
ppsInfos.back().parse(reader, maxSize > numeric_limits<uint32>::max() ? numeric_limits<uint32>::max() : static_cast<uint32>(maxSize));
|
||||
} catch (const TruncatedDataException &) {
|
||||
// TODO: log parsing error
|
||||
if (ppsInfos.back().size > maxSize - 2) {
|
||||
|
|
|
@ -108,29 +108,39 @@ void FlacMetaDataBlockPicture::parse(istream &inputStream, uint32 maxSize)
|
|||
/*!
|
||||
* \brief Returns the number of bytes make() will write.
|
||||
* \remarks Any changes to the object will invalidate this value.
|
||||
* \throws Throws an InvalidDataException() if the assigned data is too big.
|
||||
*/
|
||||
uint32 FlacMetaDataBlockPicture::requiredSize() const
|
||||
{
|
||||
return 32 + m_value.mimeType().size() + m_value.description().size() + m_value.dataSize();
|
||||
const auto requiredSize(32 + m_value.mimeType().size() + m_value.description().size() + m_value.dataSize());
|
||||
if (requiredSize > numeric_limits<uint32>::max()) {
|
||||
throw InvalidDataException();
|
||||
}
|
||||
return static_cast<uint32>(requiredSize);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the FLAC "METADATA_BLOCK_PICTURE".
|
||||
* \throws Throws an InvalidDataException() if the assigned data can not be serialized into a "METADATA_BLOCK_PICTURE" structure.
|
||||
*/
|
||||
void FlacMetaDataBlockPicture::make(ostream &outputStream)
|
||||
{
|
||||
if (m_value.mimeType().size() > numeric_limits<uint32>::max() || m_value.description().size() > numeric_limits<uint32>::max()
|
||||
|| m_value.dataSize() > numeric_limits<uint32>::max()) {
|
||||
throw InvalidDataException();
|
||||
}
|
||||
BinaryWriter writer(&outputStream);
|
||||
writer.writeUInt32BE(pictureType());
|
||||
writer.writeUInt32BE(m_value.mimeType().size());
|
||||
writer.writeUInt32BE(static_cast<uint32>(m_value.mimeType().size()));
|
||||
writer.writeString(m_value.mimeType());
|
||||
writer.writeUInt32BE(m_value.description().size());
|
||||
writer.writeUInt32BE(static_cast<uint32>(m_value.description().size()));
|
||||
writer.writeString(m_value.description());
|
||||
writer.writeUInt32BE(0); // skip width
|
||||
writer.writeUInt32BE(0); // skip height
|
||||
writer.writeUInt32BE(0); // skip color depth
|
||||
writer.writeUInt32BE(0); // skip number of colors used
|
||||
writer.writeUInt32BE(m_value.dataSize());
|
||||
writer.write(value().dataPointer(), m_value.dataSize());
|
||||
writer.writeUInt32BE(static_cast<uint32>(m_value.dataSize()));
|
||||
writer.write(value().dataPointer(), static_cast<streamoff>(m_value.dataSize()));
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
|
|
@ -71,7 +71,7 @@ void FlacStream::internalParseHeader(Diagnostics &diag)
|
|||
throw NoDataFoundException();
|
||||
}
|
||||
|
||||
m_istream->seekg(m_startOffset, ios_base::beg);
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||
char buffer[0x22];
|
||||
|
||||
// check signature
|
||||
|
@ -159,7 +159,7 @@ void FlacStream::internalParseHeader(Diagnostics &diag)
|
|||
// TODO: check first FLAC frame
|
||||
}
|
||||
|
||||
m_streamOffset = m_istream->tellg();
|
||||
m_streamOffset = static_cast<uint32>(m_istream->tellg());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -177,7 +177,7 @@ void FlacStream::internalParseHeader(Diagnostics &diag)
|
|||
uint32 FlacStream::makeHeader(ostream &outputStream, Diagnostics &diag)
|
||||
{
|
||||
istream &originalStream = m_mediaFileInfo.stream();
|
||||
originalStream.seekg(m_startOffset + 4);
|
||||
originalStream.seekg(static_cast<streamoff>(m_startOffset + 4));
|
||||
CopyHelper<512> copy;
|
||||
|
||||
// write signature
|
||||
|
@ -247,6 +247,7 @@ uint32 FlacStream::makeHeader(ostream &outputStream, Diagnostics &diag)
|
|||
outputStream.seekp(lastStartOffset);
|
||||
header.makeHeader(outputStream);
|
||||
outputStream.seekp(static_cast<streamoff>(dataSize), ios_base::cur);
|
||||
lastActuallyWrittenHeader = header;
|
||||
|
||||
// write cover fields separately as "METADATA_BLOCK_PICTURE"
|
||||
if (header.isLast()) {
|
||||
|
@ -255,13 +256,37 @@ uint32 FlacStream::makeHeader(ostream &outputStream, Diagnostics &diag)
|
|||
header.setType(FlacMetaDataBlockType::Picture);
|
||||
const auto coverFields = m_vorbisComment->fields().equal_range(coverId);
|
||||
for (auto i = coverFields.first; i != coverFields.second;) {
|
||||
lastStartOffset = outputStream.tellp();
|
||||
FlacMetaDataBlockPicture pictureBlock(i->second.value());
|
||||
pictureBlock.setPictureType(i->second.typeInfo());
|
||||
header.setDataSize(pictureBlock.requiredSize());
|
||||
header.setLast(++i == coverFields.second);
|
||||
header.makeHeader(outputStream);
|
||||
pictureBlock.make(outputStream);
|
||||
const auto lastCoverStartOffset = outputStream.tellp();
|
||||
|
||||
try {
|
||||
// write the structure
|
||||
FlacMetaDataBlockPicture pictureBlock(i->second.value());
|
||||
pictureBlock.setPictureType(i->second.typeInfo());
|
||||
header.setDataSize(pictureBlock.requiredSize());
|
||||
header.setLast(++i == coverFields.second);
|
||||
header.makeHeader(outputStream);
|
||||
pictureBlock.make(outputStream);
|
||||
|
||||
// update variables to handle the "isLast" flag
|
||||
lastStartOffset = lastCoverStartOffset;
|
||||
lastActuallyWrittenHeader = header;
|
||||
|
||||
} catch (const Failure &) {
|
||||
// we can expect nothing is written in the error case except the FLAC header, so
|
||||
// -> just add an error message
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to serialize \"METADATA_BLOCK_PICTURE\" from assigned value.",
|
||||
"write \"METADATA_BLOCK_PICTURE\" to FLAC stream");
|
||||
// -> and to recover, go back to where we were before
|
||||
outputStream.seekp(lastCoverStartOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// adjust "isLast" flag if neccassary
|
||||
if (!lastActuallyWrittenHeader.isLast()) {
|
||||
outputStream.seekp(lastStartOffset);
|
||||
lastActuallyWrittenHeader.setLast(true);
|
||||
lastActuallyWrittenHeader.makeHeader(outputStream);
|
||||
outputStream.seekp(lastActuallyWrittenHeader.dataSize());
|
||||
}
|
||||
|
||||
return static_cast<uint32>(lastStartOffset);
|
||||
|
|
|
@ -40,7 +40,7 @@ const char **Id3Genres::genreNames()
|
|||
*/
|
||||
int Id3Genres::indexFromString(const string &genre)
|
||||
{
|
||||
const char **ptr = genreNames();
|
||||
const char *const *ptr = genreNames();
|
||||
for (int index = 0; index < genreCount(); ++ptr, ++index) {
|
||||
if (genre == *ptr) {
|
||||
return index;
|
||||
|
|
|
@ -25,6 +25,9 @@ namespace Id3v2TextEncodingBytes {
|
|||
enum Id3v2TextEncodingByte : byte { Ascii, Utf16WithBom, Utf16BigEndianWithoutBom, Utf8 };
|
||||
}
|
||||
|
||||
/// \brief The maximum (supported) size of an ID3v2Frame.
|
||||
constexpr auto maxId3v2FrameDataSize(numeric_limits<uint32>::max() - 15);
|
||||
|
||||
/*!
|
||||
* \class Media::Id3v2Frame
|
||||
* \brief The Id3v2Frame class is used by Id3v2Tag to store the fields.
|
||||
|
@ -213,7 +216,11 @@ void Id3v2Frame::parse(BinaryReader &reader, uint32 version, uint32 maximalSize,
|
|||
diag.emplace_back(DiagLevel::Critical, "Decompressing failed (unknown reason).", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
m_dataSize = decompressedSize;
|
||||
if (decompressedSize > maxId3v2FrameDataSize) {
|
||||
diag.emplace_back(DiagLevel::Critical, "The decompressed data exceeds the maximum supported frame size.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
m_dataSize = static_cast<uint32>(decompressedSize);
|
||||
} else {
|
||||
buffer = make_unique<char[]>(m_dataSize);
|
||||
reader.read(buffer.get(), m_dataSize);
|
||||
|
@ -222,7 +229,7 @@ void Id3v2Frame::parse(BinaryReader &reader, uint32 version, uint32 maximalSize,
|
|||
// -> get tag value depending of field type
|
||||
if (Id3v2FrameIds::isTextFrame(id())) {
|
||||
// frame contains text
|
||||
TagTextEncoding dataEncoding = parseTextEncodingByte(*buffer.get(), diag); // the first byte stores the encoding
|
||||
TagTextEncoding dataEncoding = parseTextEncodingByte(static_cast<byte>(*buffer.get()), diag); // the first byte stores the encoding
|
||||
if ((version >= 3 && (id() == Id3v2FrameIds::lTrackPosition || id() == Id3v2FrameIds::lDiskPosition))
|
||||
|| (version < 3 && id() == Id3v2FrameIds::sTrackPosition)) {
|
||||
// the track number or the disk number frame
|
||||
|
@ -464,7 +471,11 @@ Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, byte version, Diagnostics &d
|
|||
|
||||
} else {
|
||||
// make unknown frame
|
||||
m_data = make_unique<char[]>(m_decompressedSize = value.dataSize());
|
||||
if (value.dataSize() > maxId3v2FrameDataSize) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Assigned value exceeds maximum size.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
m_data = make_unique<char[]>(m_decompressedSize = static_cast<uint32>(value.dataSize()));
|
||||
copy(value.dataPointer(), value.dataPointer() + m_decompressedSize, m_data.get());
|
||||
}
|
||||
} catch (const ConversionException &) {
|
||||
|
@ -479,9 +490,9 @@ Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, byte version, Diagnostics &d
|
|||
|
||||
// apply compression if frame should be compressed
|
||||
if (version >= 3 && m_frame.isCompressed()) {
|
||||
m_dataSize = compressBound(m_decompressedSize);
|
||||
auto compressedData = make_unique<char[]>(m_decompressedSize);
|
||||
switch (compress(reinterpret_cast<Bytef *>(compressedData.get()), reinterpret_cast<uLongf *>(&m_dataSize),
|
||||
auto compressedSize = compressBound(m_decompressedSize);
|
||||
auto compressedData = make_unique<char[]>(compressedSize);
|
||||
switch (compress(reinterpret_cast<Bytef *>(compressedData.get()), reinterpret_cast<uLongf *>(&compressedSize),
|
||||
reinterpret_cast<Bytef *>(m_data.get()), m_decompressedSize)) {
|
||||
case Z_MEM_ERROR:
|
||||
diag.emplace_back(DiagLevel::Critical, "Decompressing failed. The source buffer was too small.", context);
|
||||
|
@ -491,7 +502,12 @@ Id3v2FrameMaker::Id3v2FrameMaker(Id3v2Frame &frame, byte version, Diagnostics &d
|
|||
throw InvalidDataException();
|
||||
case Z_OK:;
|
||||
}
|
||||
if (compressedSize > maxId3v2FrameDataSize) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Compressed size exceeds maximum data size.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
m_data.swap(compressedData);
|
||||
m_dataSize = static_cast<uint32>(compressedSize);
|
||||
} else {
|
||||
m_dataSize = m_decompressedSize;
|
||||
}
|
||||
|
@ -744,15 +760,15 @@ void Id3v2Frame::parseLegacyPicture(const char *buffer, std::size_t maxSize, Tag
|
|||
throw TruncatedDataException();
|
||||
}
|
||||
const char *end = buffer + maxSize;
|
||||
auto dataEncoding = parseTextEncodingByte(*buffer, diag); // the first byte stores the encoding
|
||||
auto dataEncoding = parseTextEncodingByte(static_cast<byte>(*buffer), diag); // the first byte stores the encoding
|
||||
typeInfo = static_cast<unsigned char>(*(buffer + 4));
|
||||
auto substr = parseSubstring(buffer + 5, end - 5 - buffer, dataEncoding, true, diag);
|
||||
auto substr = parseSubstring(buffer + 5, static_cast<size_t>(end - 5 - buffer), dataEncoding, true, diag);
|
||||
tagValue.setDescription(string(get<0>(substr), get<1>(substr)), dataEncoding);
|
||||
if (get<2>(substr) >= end) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Picture frame is incomplete (actual data is missing).", context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
tagValue.assignData(get<2>(substr), end - get<2>(substr), TagDataType::Picture, dataEncoding);
|
||||
tagValue.assignData(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), TagDataType::Picture, dataEncoding);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -766,7 +782,7 @@ void Id3v2Frame::parsePicture(const char *buffer, std::size_t maxSize, TagValue
|
|||
{
|
||||
static const string context("parsing ID3v2.3 picture frame");
|
||||
const char *end = buffer + maxSize;
|
||||
auto dataEncoding = parseTextEncodingByte(*buffer, diag); // the first byte stores the encoding
|
||||
auto dataEncoding = parseTextEncodingByte(static_cast<byte>(*buffer), diag); // the first byte stores the encoding
|
||||
auto mimeTypeEncoding = TagTextEncoding::Latin1;
|
||||
auto substr = parseSubstring(buffer + 1, maxSize - 1, mimeTypeEncoding, true, diag);
|
||||
if (get<1>(substr)) {
|
||||
|
@ -781,13 +797,13 @@ void Id3v2Frame::parsePicture(const char *buffer, std::size_t maxSize, TagValue
|
|||
diag.emplace_back(DiagLevel::Critical, "Picture frame is incomplete (description and actual data are missing).", context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
substr = parseSubstring(get<2>(substr), end - get<2>(substr), dataEncoding, true, diag);
|
||||
substr = parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding, true, diag);
|
||||
tagValue.setDescription(string(get<0>(substr), get<1>(substr)), dataEncoding);
|
||||
if (get<2>(substr) >= end) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Picture frame is incomplete (actual data is missing).", context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
tagValue.assignData(get<2>(substr), end - get<2>(substr), TagDataType::Picture, dataEncoding);
|
||||
tagValue.assignData(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), TagDataType::Picture, dataEncoding);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -804,7 +820,7 @@ void Id3v2Frame::parseComment(const char *buffer, std::size_t dataSize, TagValue
|
|||
diag.emplace_back(DiagLevel::Critical, "Comment frame is incomplete.", context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
TagTextEncoding dataEncoding = parseTextEncodingByte(*buffer, diag);
|
||||
TagTextEncoding dataEncoding = parseTextEncodingByte(static_cast<byte>(*buffer), diag);
|
||||
if (*(++buffer)) {
|
||||
tagValue.setLanguage(string(buffer, 3));
|
||||
}
|
||||
|
@ -814,7 +830,7 @@ void Id3v2Frame::parseComment(const char *buffer, std::size_t dataSize, TagValue
|
|||
diag.emplace_back(DiagLevel::Critical, "Comment frame is incomplete (description not terminated?).", context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
substr = parseSubstring(get<2>(substr), end - get<2>(substr), dataEncoding, false, diag);
|
||||
substr = parseSubstring(get<2>(substr), static_cast<size_t>(end - get<2>(substr)), dataEncoding, false, diag);
|
||||
tagValue.assignData(get<0>(substr), get<1>(substr), TagDataType::Text, dataEncoding);
|
||||
}
|
||||
|
||||
|
@ -852,14 +868,14 @@ void Id3v2Frame::makeEncodingAndData(
|
|||
case TagTextEncoding::Unspecified: // assumption
|
||||
// allocate buffer
|
||||
buffer = make_unique<char[]>(bufferSize = 1 + dataSize + 1);
|
||||
buffer[0] = makeTextEncodingByte(encoding); // set text encoding byte
|
||||
buffer[0] = static_cast<char>(makeTextEncodingByte(encoding)); // set text encoding byte
|
||||
bufferDataAddress = buffer.get() + 1;
|
||||
break;
|
||||
case TagTextEncoding::Utf16LittleEndian:
|
||||
case TagTextEncoding::Utf16BigEndian:
|
||||
// allocate buffer
|
||||
buffer = make_unique<char[]>(bufferSize = 1 + 2 + dataSize + 2);
|
||||
buffer[0] = makeTextEncodingByte(encoding); // set text encoding byte
|
||||
buffer[0] = static_cast<char>(makeTextEncodingByte(encoding)); // set text encoding byte
|
||||
ConversionUtilities::LE::getBytes(
|
||||
encoding == TagTextEncoding::Utf16LittleEndian ? static_cast<uint16>(0xFEFF) : static_cast<uint16>(0xFFFE), buffer.get() + 1);
|
||||
bufferDataAddress = buffer.get() + 3;
|
||||
|
@ -919,7 +935,7 @@ void Id3v2Frame::makeLegacyPicture(unique_ptr<char[]> &buffer, uint32 &bufferSiz
|
|||
// note: encoding byte + image format + picture type byte + description size + 1 or 2 null bytes (depends on encoding) + data size
|
||||
char *offset = buffer.get();
|
||||
// write encoding byte
|
||||
*offset = makeTextEncodingByte(descriptionEncoding);
|
||||
*offset = static_cast<char>(makeTextEncodingByte(descriptionEncoding));
|
||||
// write mime type
|
||||
const char *imageFormat;
|
||||
if (picture.mimeType() == "image/jpeg") {
|
||||
|
@ -935,7 +951,7 @@ void Id3v2Frame::makeLegacyPicture(unique_ptr<char[]> &buffer, uint32 &bufferSiz
|
|||
}
|
||||
strncpy(++offset, imageFormat, 3);
|
||||
// write picture type
|
||||
*(offset += 3) = typeInfo;
|
||||
*(offset += 3) = static_cast<char>(typeInfo);
|
||||
// write description
|
||||
offset += makeBom(offset + 1, descriptionEncoding);
|
||||
if (convertedDescription.first) {
|
||||
|
@ -988,12 +1004,12 @@ void Id3v2Frame::makePicture(std::unique_ptr<char[]> &buffer, uint32 &bufferSize
|
|||
// note: encoding byte + mime type size + 0 byte + picture type byte + description size + 1 or 4 null bytes (depends on encoding) + data size
|
||||
char *offset = buffer.get();
|
||||
// write encoding byte
|
||||
*offset = makeTextEncodingByte(descriptionEncoding);
|
||||
*offset = static_cast<char>(makeTextEncodingByte(descriptionEncoding));
|
||||
// write mime type
|
||||
picture.mimeType().copy(++offset, mimeTypeSize);
|
||||
*(offset += mimeTypeSize) = 0x00; // terminate mime type
|
||||
// write picture type
|
||||
*(++offset) = typeInfo;
|
||||
*(++offset) = static_cast<char>(typeInfo);
|
||||
// write description
|
||||
offset += makeBom(offset + 1, descriptionEncoding);
|
||||
if (convertedDescription.first) {
|
||||
|
@ -1045,7 +1061,7 @@ void Id3v2Frame::makeComment(unique_ptr<char[]> &buffer, uint32 &bufferSize, con
|
|||
// note: encoding byte + language + description size + actual data size + BOMs and termination
|
||||
char *offset = buffer.get();
|
||||
// write encoding
|
||||
*offset = makeTextEncodingByte(encoding);
|
||||
*offset = static_cast<char>(makeTextEncodingByte(encoding));
|
||||
// write language
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
*(++offset) = (lng.length() > i) ? lng[i] : 0x00;
|
||||
|
|
|
@ -496,6 +496,8 @@ Id3v2TagMaker::Id3v2TagMaker(Id3v2Tag &tag, Diagnostics &diag)
|
|||
*/
|
||||
void Id3v2TagMaker::make(std::ostream &stream, uint32 padding, Diagnostics &diag)
|
||||
{
|
||||
VAR_UNUSED(diag)
|
||||
|
||||
BinaryWriter writer(&stream);
|
||||
|
||||
// write header
|
||||
|
|
|
@ -77,7 +77,7 @@ void EbmlElement::internalParse(Diagnostics &diag)
|
|||
diag.emplace_back(DiagLevel::Critical, argsToString("The EBML element at ", startOffset(), " is truncated or does not exist."), context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
stream().seekg(startOffset());
|
||||
stream().seekg(static_cast<streamoff>(startOffset()));
|
||||
|
||||
// read ID
|
||||
char buf[maximumIdLengthSupported() > maximumSizeLengthSupported() ? maximumIdLengthSupported() : maximumSizeLengthSupported()] = { 0 };
|
||||
|
@ -144,7 +144,8 @@ void EbmlElement::internalParse(Diagnostics &diag)
|
|||
}
|
||||
|
||||
// read size
|
||||
beg = static_cast<byte>(stream().peek()), mask = 0x80;
|
||||
beg = static_cast<byte>(stream().peek());
|
||||
mask = 0x80;
|
||||
m_sizeLength = 1;
|
||||
if ((m_sizeUnknown = (beg == 0xFF))) {
|
||||
// this indicates that the element size is unknown
|
||||
|
@ -225,7 +226,7 @@ void EbmlElement::internalParse(Diagnostics &diag)
|
|||
*/
|
||||
std::string EbmlElement::readString()
|
||||
{
|
||||
stream().seekg(dataOffset());
|
||||
stream().seekg(static_cast<streamoff>(dataOffset()));
|
||||
return reader().readString(dataSize());
|
||||
}
|
||||
|
||||
|
@ -237,13 +238,11 @@ std::string EbmlElement::readString()
|
|||
*/
|
||||
uint64 EbmlElement::readUInteger()
|
||||
{
|
||||
char buff[sizeof(uint64)] = { 0 };
|
||||
int i = static_cast<int>(sizeof(buff)) - dataSize();
|
||||
if (i < 0) {
|
||||
i = 0;
|
||||
}
|
||||
stream().seekg(dataOffset(), ios_base::beg);
|
||||
stream().read(buff + i, sizeof(buff) - i);
|
||||
constexpr DataSizeType maxBytesToRead = 8;
|
||||
char buff[maxBytesToRead] = { 0 };
|
||||
const auto bytesToSkip = maxBytesToRead - min(dataSize(), maxBytesToRead);
|
||||
stream().seekg(static_cast<streamoff>(dataOffset()), ios_base::beg);
|
||||
stream().read(buff + bytesToSkip, static_cast<streamoff>(sizeof(buff) - bytesToSkip));
|
||||
return BE::toUInt64(buff);
|
||||
}
|
||||
|
||||
|
@ -253,10 +252,10 @@ uint64 EbmlElement::readUInteger()
|
|||
*/
|
||||
float64 EbmlElement::readFloat()
|
||||
{
|
||||
stream().seekg(dataOffset());
|
||||
stream().seekg(static_cast<streamoff>(dataOffset()));
|
||||
switch (dataSize()) {
|
||||
case sizeof(float32):
|
||||
return reader().readFloat32BE();
|
||||
return static_cast<float64>(reader().readFloat32BE());
|
||||
case sizeof(float64):
|
||||
return reader().readFloat64BE();
|
||||
default:
|
||||
|
@ -319,7 +318,7 @@ byte EbmlElement::calculateSizeDenotationLength(uint64 size)
|
|||
byte EbmlElement::makeId(GenericFileElement::IdentifierType id, char *buff)
|
||||
{
|
||||
if (id <= 0xFF) {
|
||||
*buff = static_cast<byte>(id);
|
||||
*buff = static_cast<char>(id);
|
||||
return 1;
|
||||
} else if (id <= 0x7FFF) {
|
||||
BE::getBytes(static_cast<uint16>(id), buff);
|
||||
|
@ -345,7 +344,7 @@ byte EbmlElement::makeId(GenericFileElement::IdentifierType id, char *buff)
|
|||
byte EbmlElement::makeSizeDenotation(uint64 size, char *buff)
|
||||
{
|
||||
if (size < 126) {
|
||||
*buff = static_cast<byte>(size | 0x80);
|
||||
*buff = static_cast<char>(size | 0x80);
|
||||
return 1;
|
||||
} else if (size <= 16382ul) {
|
||||
BE::getBytes(static_cast<uint16>(size | 0x4000), buff);
|
||||
|
@ -383,7 +382,7 @@ byte EbmlElement::makeSizeDenotation(uint64 size, char *buff)
|
|||
byte EbmlElement::makeSizeDenotation(uint64 size, char *buff, byte minBytes)
|
||||
{
|
||||
if (minBytes <= 1 && size < 126) {
|
||||
*buff = static_cast<byte>(size | 0x80);
|
||||
*buff = static_cast<char>(size | 0x80);
|
||||
return 1;
|
||||
} else if (minBytes <= 2 && size <= 16382ul) {
|
||||
BE::getBytes(static_cast<uint16>(size | 0x4000), buff);
|
||||
|
@ -474,6 +473,8 @@ byte EbmlElement::makeUInteger(uint64 value, char *buff)
|
|||
* \param value Specifies the value to be written.
|
||||
* \param buff Specifies the buffer to write to.
|
||||
* \param minBytes Specifies the minimum number of bytes to use.
|
||||
* \remarks Regardless of \a minBytes, this function will never make
|
||||
* more than 8 bytes.
|
||||
*/
|
||||
byte EbmlElement::makeUInteger(uint64 value, char *buff, byte minBytes)
|
||||
{
|
||||
|
|
|
@ -173,7 +173,7 @@ void MatroskaAttachmentMaker::make(ostream &stream, Diagnostics &diag) const
|
|||
if (attachment().data() && attachment().data()->size()) {
|
||||
BE::getBytes(static_cast<uint16>(MatroskaIds::FileData), buff);
|
||||
stream.write(buff, 2);
|
||||
len = EbmlElement::makeSizeDenotation(attachment().data()->size(), buff);
|
||||
len = EbmlElement::makeSizeDenotation(static_cast<uint64>(attachment().data()->size()), buff);
|
||||
stream.write(buff, len);
|
||||
attachment().data()->copyTo(stream);
|
||||
}
|
||||
|
|
|
@ -1579,13 +1579,13 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
outputWriter.writeUInt32BE(MatroskaIds::Segment);
|
||||
sizeLength = EbmlElement::makeSizeDenotation(segment.totalDataSize, buff);
|
||||
outputStream.write(buff, sizeLength);
|
||||
segment.newDataOffset = offset = outputStream.tellp(); // store segment data offset here
|
||||
segment.newDataOffset = offset = static_cast<uint64>(outputStream.tellp()); // store segment data offset here
|
||||
|
||||
// write CRC-32 element ...
|
||||
if (segment.hasCrc32) {
|
||||
// ... if the original element had a CRC-32 element
|
||||
*buff = EbmlIds::Crc32;
|
||||
*(buff + 1) = 0x84; // length denotation: 4 byte
|
||||
*buff = static_cast<char>(EbmlIds::Crc32);
|
||||
*(buff + 1) = static_cast<char>(0x84); // length denotation: 4 byte
|
||||
// set the value after writing the element
|
||||
crc32Offsets.emplace_back(outputStream.tellp(), segment.totalDataSize);
|
||||
outputStream.write(buff, 6);
|
||||
|
@ -1736,16 +1736,16 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
switch (level2Element->id()) {
|
||||
case MatroskaIds::Position:
|
||||
// calculate new position
|
||||
sizeLength = EbmlElement::makeUInteger(
|
||||
level1Element->startOffset() - segmentData.front().newDataOffset, buff, level2Element->dataSize());
|
||||
sizeLength = EbmlElement::makeUInteger(level1Element->startOffset() - segmentData.front().newDataOffset, buff,
|
||||
level2Element->dataSize() > 8 ? 8 : static_cast<byte>(level2Element->dataSize()));
|
||||
// new position can only applied if it doesn't need more bytes than the previous position
|
||||
if (level2Element->dataSize() < sizeLength) {
|
||||
// can't update position -> void position elements ("Position"-elements seem a bit useless anyways)
|
||||
outputStream.seekp(level2Element->startOffset());
|
||||
outputStream.seekp(static_cast<streamoff>(level2Element->startOffset()));
|
||||
outputStream.put(static_cast<char>(EbmlIds::Void));
|
||||
} else {
|
||||
// update position
|
||||
outputStream.seekp(level2Element->dataOffset());
|
||||
outputStream.seekp(static_cast<streamoff>(level2Element->dataOffset()));
|
||||
outputStream.write(buff, sizeLength);
|
||||
}
|
||||
break;
|
||||
|
@ -1754,7 +1754,7 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
}
|
||||
}
|
||||
// skip existing "Cluster"-elements
|
||||
outputStream.seekp(segment.clusterEndOffset);
|
||||
outputStream.seekp(static_cast<streamoff>(segment.clusterEndOffset));
|
||||
}
|
||||
|
||||
progress.updateStep("Writing segment tail ...");
|
||||
|
@ -1847,8 +1847,8 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
|||
if (!crc32Offsets.empty()) {
|
||||
progress.updateStep("Updating CRC-32 checksums ...");
|
||||
for (const auto &crc32Offset : crc32Offsets) {
|
||||
outputStream.seekg(get<0>(crc32Offset) + 6);
|
||||
outputStream.seekp(get<0>(crc32Offset) + 2);
|
||||
outputStream.seekg(static_cast<streamoff>(get<0>(crc32Offset) + 6));
|
||||
outputStream.seekp(static_cast<streamoff>(get<0>(crc32Offset) + 2));
|
||||
writer().writeUInt32LE(reader().readCrc32(get<1>(crc32Offset) - 6));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ void MatroskaCuePositionUpdater::make(ostream &stream, Diagnostics &diag)
|
|||
break;
|
||||
case MatroskaIds::CuePoint:
|
||||
// write "CuePoint"-element
|
||||
stream.put(MatroskaIds::CuePoint);
|
||||
stream.put(static_cast<char>(MatroskaIds::CuePoint));
|
||||
len = EbmlElement::makeSizeDenotation(m_sizes[cuePointElement], buff);
|
||||
stream.write(buff, len);
|
||||
for (EbmlElement *cuePointChild = cuePointElement->firstChild(); cuePointChild; cuePointChild = cuePointChild->nextSibling()) {
|
||||
|
@ -282,7 +282,7 @@ void MatroskaCuePositionUpdater::make(ostream &stream, Diagnostics &diag)
|
|||
break;
|
||||
case MatroskaIds::CueTrackPositions:
|
||||
// write "CueTrackPositions"-element
|
||||
stream.put(MatroskaIds::CueTrackPositions);
|
||||
stream.put(static_cast<char>(MatroskaIds::CueTrackPositions));
|
||||
len = EbmlElement::makeSizeDenotation(m_sizes[cuePointChild], buff);
|
||||
stream.write(buff, len);
|
||||
for (EbmlElement *cueTrackPositionsChild = cuePointChild->firstChild(); cueTrackPositionsChild;
|
||||
|
@ -314,7 +314,7 @@ void MatroskaCuePositionUpdater::make(ostream &stream, Diagnostics &diag)
|
|||
break;
|
||||
case MatroskaIds::CueReference:
|
||||
// write "CueReference"-element
|
||||
stream.put(MatroskaIds::CueRefTime);
|
||||
stream.put(static_cast<char>(MatroskaIds::CueRefTime));
|
||||
len = EbmlElement::makeSizeDenotation(m_sizes[cueTrackPositionsChild], buff);
|
||||
stream.write(buff, len);
|
||||
for (EbmlElement *cueReferenceChild = cueTrackPositionsChild->firstChild(); cueReferenceChild;
|
||||
|
|
|
@ -26,7 +26,11 @@ void MatroskaSeekInfo::shift(uint64 start, int64 amount)
|
|||
{
|
||||
for (auto &info : m_info) {
|
||||
if (get<1>(info) >= start) {
|
||||
get<1>(info) += amount;
|
||||
if (amount > 0) {
|
||||
get<1>(info) += static_cast<uint64>(amount);
|
||||
} else {
|
||||
get<1>(info) -= static_cast<uint64>(-amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +110,8 @@ void MatroskaSeekInfo::parse(EbmlElement *seekHeadElement, Diagnostics &diag)
|
|||
*/
|
||||
void MatroskaSeekInfo::make(ostream &stream, Diagnostics &diag)
|
||||
{
|
||||
VAR_UNUSED(diag)
|
||||
|
||||
uint64 totalSize = 0;
|
||||
char buff0[8];
|
||||
char buff1[8];
|
||||
|
@ -129,16 +135,16 @@ void MatroskaSeekInfo::make(ostream &stream, Diagnostics &diag)
|
|||
// "Seek" header
|
||||
BE::getBytes(static_cast<uint16>(MatroskaIds::Seek), buff2);
|
||||
stream.write(buff2, 2);
|
||||
stream.put(0x80 | (2 + 1 + sizeLength0 + 2 + 1 + sizeLength1));
|
||||
stream.put(static_cast<char>(0x80 | (2 + 1 + sizeLength0 + 2 + 1 + sizeLength1)));
|
||||
// "SeekID" element
|
||||
BE::getBytes(static_cast<uint16>(MatroskaIds::SeekID), buff2);
|
||||
stream.write(buff2, 2);
|
||||
stream.put(0x80 | sizeLength0);
|
||||
stream.put(static_cast<char>(0x80 | sizeLength0));
|
||||
stream.write(buff0, sizeLength0);
|
||||
// "SeekPosition" element
|
||||
BE::getBytes(static_cast<uint16>(MatroskaIds::SeekPosition), buff2);
|
||||
stream.write(buff2, 2);
|
||||
stream.put(0x80 | sizeLength1);
|
||||
stream.put(static_cast<char>(0x80 | sizeLength1));
|
||||
stream.write(buff1, sizeLength1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,12 @@ void MatroskaTag::parse(EbmlElement &tagElement, Diagnostics &diag)
|
|||
{
|
||||
static const string context("parsing Matroska tag");
|
||||
tagElement.parse(diag);
|
||||
m_size = tagElement.totalSize();
|
||||
if (tagElement.totalSize() > numeric_limits<uint32>::max()) {
|
||||
// FIXME: Support this? Likely not very useful in practise.
|
||||
diag.emplace_back(DiagLevel::Critical, "Matroska tag is too big.", context);
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_size = static_cast<uint32>(tagElement.totalSize());
|
||||
for (EbmlElement *child = tagElement.firstChild(); child; child = child->nextSibling()) {
|
||||
child->parse(diag);
|
||||
switch (child->id()) {
|
||||
|
@ -292,7 +297,7 @@ void MatroskaTagMaker::make(ostream &stream) const
|
|||
BE::getBytes(static_cast<uint16>(MatroskaIds::TargetTypeValue), buff);
|
||||
stream.write(buff, 2);
|
||||
len = EbmlElement::makeUInteger(t.level(), buff);
|
||||
stream.put(0x80 | len);
|
||||
stream.put(static_cast<char>(0x80 | len));
|
||||
stream.write(buff, len);
|
||||
}
|
||||
if (!t.levelName().empty()) {
|
||||
|
@ -311,7 +316,7 @@ void MatroskaTagMaker::make(ostream &stream) const
|
|||
BE::getBytes(pair.first, buff);
|
||||
for (auto uid : pair.second) {
|
||||
len = EbmlElement::makeUInteger(uid, buff + 3);
|
||||
*(buff + 2) = 0x80 | len;
|
||||
*(buff + 2) = static_cast<char>(0x80 | len);
|
||||
stream.write(buff, 3 + len);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,8 +70,8 @@ void MatroskaTagField::reparse(EbmlElement &simpleTagElement, Diagnostics &diag,
|
|||
case MatroskaIds::TagBinary:
|
||||
if (value().isEmpty()) {
|
||||
unique_ptr<char[]> buffer = make_unique<char[]>(child->dataSize());
|
||||
child->stream().seekg(child->dataOffset());
|
||||
child->stream().read(buffer.get(), child->dataSize());
|
||||
child->stream().seekg(static_cast<streamoff>(child->dataOffset()));
|
||||
child->stream().read(buffer.get(), static_cast<streamoff>(child->dataSize()));
|
||||
switch (child->id()) {
|
||||
case MatroskaIds::TagString:
|
||||
value().assignData(move(buffer), child->dataSize(), TagDataType::Text, TagTextEncoding::Utf8);
|
||||
|
|
|
@ -442,13 +442,13 @@ void MatroskaTrack::internalParseHeader(Diagnostics &diag)
|
|||
}
|
||||
|
||||
// read further information from the CodecPrivate element for some codecs
|
||||
EbmlElement *codecPrivateElement;
|
||||
switch (m_format.general) {
|
||||
EbmlElement *codecPrivateElement;
|
||||
case GeneralMediaFormat::MicrosoftVideoCodecManager:
|
||||
if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
|
||||
// parse bitmap info header to determine actual format
|
||||
if (codecPrivateElement->dataSize() >= 0x28) {
|
||||
m_istream->seekg(codecPrivateElement->dataOffset());
|
||||
m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
|
||||
BitmapInfoHeader bitmapInfoHeader;
|
||||
bitmapInfoHeader.parse(reader());
|
||||
m_formatId.reserve(m_formatId.size() + 7);
|
||||
|
@ -465,7 +465,7 @@ void MatroskaTrack::internalParseHeader(Diagnostics &diag)
|
|||
if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
|
||||
// parse WAVE header to determine actual format
|
||||
if (codecPrivateElement->dataSize() >= 16) {
|
||||
m_istream->seekg(codecPrivateElement->dataOffset());
|
||||
m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
|
||||
WaveFormatHeader waveFormatHeader;
|
||||
waveFormatHeader.parse(reader());
|
||||
WaveAudioStream::addInfo(waveFormatHeader, *this);
|
||||
|
@ -502,7 +502,7 @@ void MatroskaTrack::internalParseHeader(Diagnostics &diag)
|
|||
if ((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate, diag))) {
|
||||
auto avcConfig = make_unique<TagParser::AvcConfiguration>();
|
||||
try {
|
||||
m_istream->seekg(codecPrivateElement->dataOffset());
|
||||
m_istream->seekg(static_cast<streamoff>(codecPrivateElement->dataOffset()));
|
||||
avcConfig->parse(m_reader, codecPrivateElement->dataSize());
|
||||
Mp4Track::addInfo(*avcConfig, *this);
|
||||
} catch (const TruncatedDataException &) {
|
||||
|
|
|
@ -1005,9 +1005,8 @@ const char *mediaTypeName(MediaType mediaType)
|
|||
return "Control";
|
||||
case MediaType::Unknown:
|
||||
return "Other";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
|
|
@ -68,7 +68,7 @@ void Mp4Atom::internalParse(Diagnostics &diag)
|
|||
context);
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
stream().seekg(startOffset());
|
||||
stream().seekg(static_cast<streamoff>(startOffset()));
|
||||
m_dataSize = reader().readUInt32BE();
|
||||
if (m_dataSize == 0) {
|
||||
// atom size extends to rest of the file/enclosing container
|
||||
|
@ -122,6 +122,11 @@ void Mp4Atom::internalParse(Diagnostics &diag)
|
|||
* \brief This function helps to write the atom size after writing an atom to a stream.
|
||||
* \param stream Specifies the stream.
|
||||
* \param startOffset Specifies the start offset of the atom.
|
||||
* \remarks The caller must ensure that no seek before \a startOffset happended.
|
||||
* \throw The caller has to be sure, that the number of written bytes does not exceed
|
||||
* maximum of an 32-bit unsigned integer. Otherwise the function will throw
|
||||
* Failure and Mp4Atom::seekBackAndWriteAtomSize64 should be used instead.
|
||||
* \todo Add a version which creates a diag message (in addition to throwing an exception).
|
||||
*
|
||||
* This function seeks back to the start offset and writes the difference between the
|
||||
* previous offset and the start offset as 32-bit unsigned integer to the \a stream.
|
||||
|
@ -130,9 +135,13 @@ void Mp4Atom::internalParse(Diagnostics &diag)
|
|||
void Mp4Atom::seekBackAndWriteAtomSize(std::ostream &stream, const ostream::pos_type &startOffset)
|
||||
{
|
||||
ostream::pos_type currentOffset = stream.tellp();
|
||||
const auto atomSize(currentOffset - startOffset);
|
||||
if (atomSize > numeric_limits<uint32>::max()) {
|
||||
throw Failure();
|
||||
}
|
||||
stream.seekp(startOffset);
|
||||
BinaryWriter writer(&stream);
|
||||
writer.writeUInt32BE(currentOffset - startOffset);
|
||||
writer.writeUInt32BE(static_cast<uint32>(atomSize));
|
||||
stream.seekp(currentOffset);
|
||||
}
|
||||
|
||||
|
@ -140,6 +149,7 @@ void Mp4Atom::seekBackAndWriteAtomSize(std::ostream &stream, const ostream::pos_
|
|||
* \brief This function helps to write the atom size after writing an atom to a stream.
|
||||
* \param stream Specifies the stream.
|
||||
* \param startOffset Specifies the start offset of the atom.
|
||||
* \remarks The caller must ensure that no seek before \a startOffset happended.
|
||||
*
|
||||
* This function seeks back to the start offset and writes the difference between the
|
||||
* previous offset and the start offset as 64-bit unsigned integer to the \a stream.
|
||||
|
@ -152,7 +162,7 @@ void Mp4Atom::seekBackAndWriteAtomSize64(std::ostream &stream, const ostream::po
|
|||
BinaryWriter writer(&stream);
|
||||
writer.writeUInt32BE(1);
|
||||
stream.seekp(4, ios_base::cur);
|
||||
writer.writeUInt64BE(currentOffset - startOffset);
|
||||
writer.writeUInt64BE(static_cast<uint64>(currentOffset - startOffset));
|
||||
stream.seekp(currentOffset);
|
||||
}
|
||||
|
||||
|
|
|
@ -644,8 +644,8 @@ calculatePadding:
|
|||
// write padding
|
||||
if (newPadding) {
|
||||
// write free atom header
|
||||
if (newPadding < 0xFFFFFFFF) {
|
||||
outputWriter.writeUInt32BE(newPadding);
|
||||
if (newPadding < numeric_limits<uint32>::max()) {
|
||||
outputWriter.writeUInt32BE(static_cast<uint32>(newPadding));
|
||||
outputWriter.writeUInt32BE(Mp4AtomIds::Free);
|
||||
newPadding -= 8;
|
||||
} else {
|
||||
|
@ -678,7 +678,7 @@ calculatePadding:
|
|||
break;
|
||||
} else {
|
||||
// store media data offsets when not writing chunk-by-chunk to be able to update chunk offset table
|
||||
origMediaDataOffsets.push_back(level0Atom->startOffset());
|
||||
origMediaDataOffsets.push_back(static_cast<int64>(level0Atom->startOffset()));
|
||||
newMediaDataOffsets.push_back(outputStream.tellp());
|
||||
}
|
||||
FALLTHROUGH;
|
||||
|
@ -741,8 +741,8 @@ calculatePadding:
|
|||
// still chunks to be copied (of this track)?
|
||||
if (chunkIndexWithinTrack < chunkOffsetTable.size() && chunkIndexWithinTrack < chunkSizesTable.size()) {
|
||||
// copy chunk, update entry in chunk offset table
|
||||
sourceStream.seekg(chunkOffsetTable[chunkIndexWithinTrack]);
|
||||
chunkOffsetTable[chunkIndexWithinTrack] = outputStream.tellp();
|
||||
sourceStream.seekg(static_cast<streamoff>(chunkOffsetTable[chunkIndexWithinTrack]));
|
||||
chunkOffsetTable[chunkIndexWithinTrack] = static_cast<uint64>(outputStream.tellp());
|
||||
copyHelper.copy(sourceStream, outputStream, chunkSizesTable[chunkIndexWithinTrack]);
|
||||
|
||||
// update counter / status
|
||||
|
@ -916,12 +916,13 @@ void Mp4Container::updateOffsets(const std::vector<int64> &oldMdatOffsets, const
|
|||
uint64 off = reader().readUInt64BE();
|
||||
for (auto iOld = oldMdatOffsets.cbegin(), iNew = newMdatOffsets.cbegin(), end = oldMdatOffsets.cend(); iOld != end;
|
||||
++iOld, ++iNew) {
|
||||
if (off >= static_cast<uint64>(*iOld)) {
|
||||
off += (*iNew - *iOld);
|
||||
stream().seekp(static_cast<iostream::off_type>(tfhdAtom->dataOffset()) + 8);
|
||||
writer().writeUInt64BE(off);
|
||||
break;
|
||||
if (off < static_cast<uint64>(*iOld)) {
|
||||
continue;
|
||||
}
|
||||
off += static_cast<uint64>(*iNew - *iOld);
|
||||
stream().seekp(static_cast<iostream::off_type>(tfhdAtom->dataOffset()) + 8);
|
||||
writer().writeUInt64BE(off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (tfhdAtomCount) {
|
||||
|
|
|
@ -27,10 +27,12 @@ Mp4ExtendedFieldId::Mp4ExtendedFieldId(KnownField field)
|
|||
{
|
||||
switch (field) {
|
||||
case KnownField::EncoderSettings:
|
||||
mean = Mp4TagExtendedMeanIds::iTunes, name = Mp4TagExtendedNameIds::cdec;
|
||||
mean = Mp4TagExtendedMeanIds::iTunes;
|
||||
name = Mp4TagExtendedNameIds::cdec;
|
||||
break;
|
||||
case KnownField::RecordLabel:
|
||||
mean = Mp4TagExtendedMeanIds::iTunes, name = Mp4TagExtendedNameIds::label;
|
||||
mean = Mp4TagExtendedMeanIds::iTunes;
|
||||
name = Mp4TagExtendedNameIds::label;
|
||||
updateOnly = true; // set record label via extended field only if extended field is already present
|
||||
break;
|
||||
default:
|
||||
|
@ -319,7 +321,11 @@ void Mp4Tag::parse(Mp4Atom &metaAtom, Diagnostics &diag)
|
|||
static const string context("parsing MP4 tag");
|
||||
istream &stream = metaAtom.container().stream();
|
||||
BinaryReader &reader = metaAtom.container().reader();
|
||||
m_size = metaAtom.totalSize();
|
||||
if (metaAtom.totalSize() > numeric_limits<uint32>::max()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Can't handle such big \"meta\" atoms.", context);
|
||||
throw NotImplementedException();
|
||||
}
|
||||
m_size = static_cast<uint32>(metaAtom.totalSize());
|
||||
Mp4Atom *subAtom = nullptr;
|
||||
try {
|
||||
metaAtom.childById(Mp4AtomIds::HandlerReference, diag);
|
||||
|
@ -327,7 +333,7 @@ void Mp4Tag::parse(Mp4Atom &metaAtom, Diagnostics &diag)
|
|||
diag.emplace_back(DiagLevel::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
||||
}
|
||||
if (subAtom) {
|
||||
stream.seekg(subAtom->startOffset() + subAtom->headerSize());
|
||||
stream.seekg(static_cast<streamoff>(subAtom->startOffset() + subAtom->headerSize()));
|
||||
int versionByte = reader.readByte();
|
||||
if (versionByte != 0) {
|
||||
diag.emplace_back(DiagLevel::Warning, "Version is unknown.", context);
|
||||
|
@ -351,20 +357,19 @@ void Mp4Tag::parse(Mp4Atom &metaAtom, Diagnostics &diag)
|
|||
} catch (const Failure &) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse child atoms of meta atom (stores hdlr and ilst atoms).", context);
|
||||
}
|
||||
if (subAtom) {
|
||||
for (auto *child = subAtom->firstChild(); child; child = child->nextSibling()) {
|
||||
Mp4TagField tagField;
|
||||
try {
|
||||
child->parse(diag);
|
||||
tagField.reparse(*child, diag);
|
||||
fields().emplace(child->id(), move(tagField));
|
||||
} catch (const Failure &) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!subAtom) {
|
||||
diag.emplace_back(DiagLevel::Warning, "No ilst atom found (stores attached meta information).", context);
|
||||
throw NoDataFoundException();
|
||||
}
|
||||
for (auto *child = subAtom->firstChild(); child; child = child->nextSibling()) {
|
||||
Mp4TagField tagField;
|
||||
try {
|
||||
child->parse(diag);
|
||||
tagField.reparse(*child, diag);
|
||||
fields().emplace(child->id(), move(tagField));
|
||||
} catch (const Failure &) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -429,6 +434,10 @@ Mp4TagMaker::Mp4TagMaker(Mp4Tag &tag, Diagnostics &diag)
|
|||
if (m_ilstSize != 8) {
|
||||
m_metaSize += m_ilstSize;
|
||||
}
|
||||
if (m_metaSize >= numeric_limits<uint32>::max()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Making such big tags is not implemented.", "making MP4 tag");
|
||||
throw NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -442,7 +451,7 @@ void Mp4TagMaker::make(ostream &stream, Diagnostics &diag)
|
|||
{
|
||||
// write meta head
|
||||
BinaryWriter writer(&stream);
|
||||
writer.writeUInt32BE(m_metaSize);
|
||||
writer.writeUInt32BE(static_cast<uint32>(m_metaSize));
|
||||
writer.writeUInt32BE(Mp4AtomIds::Meta);
|
||||
// write hdlr atom
|
||||
static const byte hdlrData[37] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -450,7 +459,7 @@ void Mp4TagMaker::make(ostream &stream, Diagnostics &diag)
|
|||
stream.write(reinterpret_cast<const char *>(hdlrData), sizeof(hdlrData));
|
||||
if (m_ilstSize != 8) {
|
||||
// write ilst head
|
||||
writer.writeUInt32BE(m_ilstSize);
|
||||
writer.writeUInt32BE(static_cast<uint32>(m_ilstSize));
|
||||
writer.writeUInt32BE(Mp4AtomIds::ItunesList);
|
||||
// write fields
|
||||
for (auto &maker : m_maker) {
|
||||
|
|
|
@ -98,7 +98,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
stream.seekg(dataAtom->dataOffset());
|
||||
stream.seekg(static_cast<streamoff>(dataAtom->dataOffset()));
|
||||
if (reader.readByte() != 0) {
|
||||
diag.emplace_back(DiagLevel::Warning,
|
||||
"The version indicator byte is not zero, the tag atom might be unsupported and hence not be parsed correctly.", context);
|
||||
|
@ -117,7 +117,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
switch (m_parsedRawDataType) {
|
||||
case RawDataType::Utf8:
|
||||
case RawDataType::Utf16:
|
||||
stream.seekg(dataAtom->dataOffset() + 8);
|
||||
stream.seekg(static_cast<streamoff>(dataAtom->dataOffset() + 8));
|
||||
value().assignText(reader.readString(dataAtom->dataSize() - 8),
|
||||
(m_parsedRawDataType == RawDataType::Utf16) ? TagTextEncoding::Utf16BigEndian : TagTextEncoding::Utf8);
|
||||
break;
|
||||
|
@ -140,10 +140,10 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
break;
|
||||
default:;
|
||||
}
|
||||
const streamsize coverSize = dataAtom->dataSize() - 8;
|
||||
unique_ptr<char[]> coverData = make_unique<char[]>(coverSize);
|
||||
const auto coverSize = static_cast<streamoff>(dataAtom->dataSize() - 8);
|
||||
auto coverData = make_unique<char[]>(static_cast<size_t>(coverSize));
|
||||
stream.read(coverData.get(), coverSize);
|
||||
value().assignData(move(coverData), coverSize, TagDataType::Picture);
|
||||
value().assignData(move(coverData), static_cast<size_t>(coverSize), TagDataType::Picture);
|
||||
break;
|
||||
}
|
||||
case RawDataType::BeSignedInt: {
|
||||
|
@ -215,13 +215,13 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
}
|
||||
break;
|
||||
default: // no supported data type, read raw data
|
||||
streamsize dataSize = dataAtom->dataSize() - 8;
|
||||
unique_ptr<char[]> data = make_unique<char[]>(dataSize);
|
||||
const auto dataSize = static_cast<streamsize>(dataAtom->dataSize() - 8);
|
||||
auto data = make_unique<char[]>(static_cast<size_t>(dataSize));
|
||||
stream.read(data.get(), dataSize);
|
||||
if (ilstChild.id() == Mp4TagAtomIds::Cover) {
|
||||
value().assignData(move(data), dataSize, TagDataType::Picture);
|
||||
value().assignData(move(data), static_cast<size_t>(dataSize), TagDataType::Picture);
|
||||
} else {
|
||||
value().assignData(move(data), dataSize, TagDataType::Undefined);
|
||||
value().assignData(move(data), static_cast<size_t>(dataSize), TagDataType::Undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
stream.seekg(dataAtom->dataOffset() + 4);
|
||||
stream.seekg(static_cast<streamoff>(dataAtom->dataOffset() + 4));
|
||||
m_mean = reader.readString(dataAtom->dataSize() - 4);
|
||||
} else if (dataAtom->id() == Mp4AtomIds::Name) {
|
||||
if (dataAtom->dataSize() < 4) {
|
||||
|
@ -251,7 +251,7 @@ void Mp4TagField::reparse(Mp4Atom &ilstChild, Diagnostics &diag)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
stream.seekg(dataAtom->dataOffset() + 4);
|
||||
stream.seekg(static_cast<streamoff>(dataAtom->dataOffset() + 4));
|
||||
m_name = reader.readString(dataAtom->dataSize() - 4);
|
||||
} else {
|
||||
diag.emplace_back(DiagLevel::Warning,
|
||||
|
@ -501,10 +501,10 @@ Mp4TagFieldMaker::Mp4TagFieldMaker(Mp4TagField &field, Diagnostics &diag)
|
|||
if (number <= numeric_limits<uint16>::max() && number >= numeric_limits<uint16>::min()) {
|
||||
m_writer.writeUInt16BE(static_cast<uint16>(number));
|
||||
} else if (number > 0) {
|
||||
m_writer.writeUInt32BE(number);
|
||||
m_writer.writeUInt32BE(static_cast<uint32>(number));
|
||||
} else {
|
||||
throw ConversionException(
|
||||
"Negative integer can not be assigned to the field with the id \"" % interpretIntegerAsString<uint32>(m_field.id()) + "\".");
|
||||
"Negative integer can not be assigned to the field with the ID \"" % interpretIntegerAsString<uint32>(m_field.id()) + "\".");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -531,7 +531,7 @@ Mp4TagFieldMaker::Mp4TagFieldMaker(Mp4TagField &field, Diagnostics &diag)
|
|||
break;
|
||||
}
|
||||
case Mp4TagAtomIds::PreDefinedGenre:
|
||||
m_writer.writeUInt16BE(m_field.value().toStandardGenreIndex());
|
||||
m_writer.writeUInt16BE(static_cast<uint16>(m_field.value().toStandardGenreIndex()));
|
||||
break;
|
||||
default:; // leave converted data empty to write original data later
|
||||
}
|
||||
|
@ -553,6 +553,10 @@ Mp4TagFieldMaker::Mp4TagFieldMaker(Mp4TagField &field, Diagnostics &diag)
|
|||
m_totalSize = 8 // calculate entire size
|
||||
+ (m_field.name().empty() ? 0 : (12 + m_field.name().length())) + (m_field.mean().empty() ? 0 : (12 + m_field.mean().length()))
|
||||
+ (m_dataSize ? (16 + m_dataSize) : 0);
|
||||
if (m_totalSize > numeric_limits<uint32>::max()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Making a such big MP4 tag field is not supported.", context);
|
||||
throw NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -566,25 +570,25 @@ void Mp4TagFieldMaker::make(ostream &stream)
|
|||
{
|
||||
m_writer.setStream(&stream);
|
||||
// size of entire tag atom
|
||||
m_writer.writeUInt32BE(m_totalSize);
|
||||
m_writer.writeUInt32BE(static_cast<uint32>(m_totalSize));
|
||||
// id of tag atom
|
||||
m_writer.writeUInt32BE(m_field.id());
|
||||
if (!m_field.mean().empty()) {
|
||||
// write "mean"
|
||||
m_writer.writeUInt32BE(12 + m_field.mean().size());
|
||||
m_writer.writeUInt32BE(static_cast<uint32>(12 + m_field.mean().size()));
|
||||
m_writer.writeUInt32BE(Mp4AtomIds::Mean);
|
||||
m_writer.writeUInt32BE(0);
|
||||
m_writer.writeString(m_field.mean());
|
||||
}
|
||||
if (!m_field.name().empty()) {
|
||||
// write "name"
|
||||
m_writer.writeUInt32BE(12 + m_field.name().length());
|
||||
m_writer.writeUInt32BE(static_cast<uint32>(12 + m_field.name().length()));
|
||||
m_writer.writeUInt32BE(Mp4AtomIds::Name);
|
||||
m_writer.writeUInt32BE(0);
|
||||
m_writer.writeString(m_field.name());
|
||||
}
|
||||
if (!m_field.value().isEmpty()) { // write data
|
||||
m_writer.writeUInt32BE(16 + m_dataSize); // size of data atom
|
||||
m_writer.writeUInt32BE(static_cast<uint32>(16 + m_dataSize)); // size of data atom
|
||||
m_writer.writeUInt32BE(Mp4AtomIds::Data); // id of data atom
|
||||
m_writer.writeByte(0); // version
|
||||
m_writer.writeUInt24BE(m_rawDataType);
|
||||
|
@ -595,7 +599,7 @@ void Mp4TagFieldMaker::make(ostream &stream)
|
|||
stream << m_convertedData.rdbuf();
|
||||
} else {
|
||||
// no conversion was needed, write data directly from tag value
|
||||
stream.write(m_field.value().dataPointer(), m_field.value().dataSize());
|
||||
stream.write(m_field.value().dataPointer(), static_cast<streamoff>(m_field.value().dataSize()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1219,8 +1219,8 @@ void Mp4Track::makeTrackHeader(Diagnostics &diag)
|
|||
// make further values, either from existing tkhd atom or just some defaults
|
||||
if (info.canUseExisting) {
|
||||
// write all bytes after the previously determined additionalDataOffset
|
||||
m_ostream->write(
|
||||
m_tkhdAtom->buffer().get() + m_tkhdAtom->headerSize() + info.additionalDataOffset, m_tkhdAtom->dataSize() - info.additionalDataOffset);
|
||||
m_ostream->write(m_tkhdAtom->buffer().get() + m_tkhdAtom->headerSize() + info.additionalDataOffset,
|
||||
static_cast<streamoff>(m_tkhdAtom->dataSize() - info.additionalDataOffset));
|
||||
// discard the buffer again if it wasn't present before
|
||||
if (info.discardBuffer) {
|
||||
m_tkhdAtom->discardBuffer();
|
||||
|
|
|
@ -62,7 +62,7 @@ void Mpeg4Descriptor::internalParse(Diagnostics &diag)
|
|||
"parsing MPEG-4 descriptor");
|
||||
throw TruncatedDataException();
|
||||
}
|
||||
stream().seekg(startOffset());
|
||||
stream().seekg(static_cast<streamoff>(startOffset()));
|
||||
// read ID
|
||||
m_idLength = m_sizeLength = 1;
|
||||
m_id = reader().readByte();
|
||||
|
@ -76,18 +76,20 @@ void Mpeg4Descriptor::internalParse(Diagnostics &diag)
|
|||
// check whether the denoted data size exceeds the available data size
|
||||
if (maxTotalSize() < totalSize()) {
|
||||
diag.emplace_back(DiagLevel::Warning, "The descriptor seems to be truncated; unable to parse siblings of that ", parsingContext());
|
||||
m_dataSize = maxTotalSize(); // using max size instead
|
||||
m_dataSize = static_cast<uint32>(maxTotalSize()); // using max size instead
|
||||
}
|
||||
m_firstChild.reset();
|
||||
Mpeg4Descriptor *sibling = nullptr;
|
||||
if (totalSize() < maxTotalSize()) {
|
||||
if (parent()) {
|
||||
sibling = new Mpeg4Descriptor(*(parent()), startOffset() + totalSize());
|
||||
} else {
|
||||
sibling = new Mpeg4Descriptor(container(), startOffset() + totalSize(), maxTotalSize() - totalSize());
|
||||
}
|
||||
|
||||
// check for siblings
|
||||
if (totalSize() >= maxTotalSize()) {
|
||||
m_nextSibling.reset();
|
||||
return;
|
||||
}
|
||||
if (parent()) {
|
||||
m_nextSibling.reset(new Mpeg4Descriptor(*(parent()), startOffset() + totalSize()));
|
||||
} else {
|
||||
m_nextSibling.reset(new Mpeg4Descriptor(container(), startOffset() + totalSize(), maxTotalSize() - totalSize()));
|
||||
}
|
||||
m_nextSibling.reset(sibling);
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace TagParser {
|
|||
void MpegAudioFrameStream::addInfo(const MpegAudioFrame &frame, AbstractTrack &track)
|
||||
{
|
||||
track.m_version = frame.mpegVersion();
|
||||
track.m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, frame.layer());
|
||||
track.m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, static_cast<unsigned char>(frame.layer()));
|
||||
track.m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2;
|
||||
track.m_channelConfig = static_cast<byte>(frame.channelMode());
|
||||
track.m_samplingFrequency = frame.samplingFrequency();
|
||||
|
@ -42,7 +42,7 @@ void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag)
|
|||
} else {
|
||||
m_size = static_cast<uint64>(m_istream->tellg()) + 125u - m_startOffset;
|
||||
}
|
||||
m_istream->seekg(m_startOffset, ios_base::beg);
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||
// parse frame header
|
||||
m_frames.emplace_back();
|
||||
MpegAudioFrame &frame = m_frames.back();
|
||||
|
@ -60,7 +60,7 @@ void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag)
|
|||
? ((static_cast<double>(m_size) * 8.0)
|
||||
/ (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
|
||||
: frame.bitrate();
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bytesPerSecond = m_bitrate * 125));
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bytesPerSecond = static_cast<uint32>(m_bitrate * 125)));
|
||||
}
|
||||
|
||||
} // namespace TagParser
|
||||
|
|
|
@ -112,6 +112,7 @@ OggVorbisComment *OggContainer::createTag(const TagTarget &target)
|
|||
} else {
|
||||
// TODO: error handling?
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
// TODO: allow adding tags to FLAC tracks (not really important, because a tag should always be present)
|
||||
|
@ -349,7 +350,7 @@ void OggContainer::makeVorbisCommentSegment(stringstream &buffer, CopyHelper<653
|
|||
comment->make(buffer, VorbisCommentFlags::NoSignature | VorbisCommentFlags::NoFramingByte, diag);
|
||||
|
||||
// finally make the header
|
||||
header.setDataSize(buffer.tellp() - offset - 4);
|
||||
header.setDataSize(static_cast<uint32>(buffer.tellp() - offset - 4));
|
||||
if (header.dataSize() > 0xFFFFFF) {
|
||||
diag.emplace_back(
|
||||
DiagLevel::Critical, "Size of Vorbis comment exceeds size limit for FLAC \"METADATA_BLOCK_HEADER\".", "making Vorbis Comment");
|
||||
|
@ -361,7 +362,7 @@ void OggContainer::makeVorbisCommentSegment(stringstream &buffer, CopyHelper<653
|
|||
}
|
||||
default:;
|
||||
}
|
||||
newSegmentSizes.push_back(buffer.tellp() - offset);
|
||||
newSegmentSizes.push_back(static_cast<uint32>(buffer.tellp() - offset));
|
||||
}
|
||||
|
||||
void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||
|
@ -430,51 +431,52 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
uint64 segmentOffset = m_iterator.currentSegmentOffset();
|
||||
vector<uint32>::size_type segmentIndex = 0;
|
||||
for (const auto segmentSize : currentPage.segmentSizes()) {
|
||||
if (segmentSize) {
|
||||
// check whether this segment contains the Vorbis Comment
|
||||
if ((m_iterator.currentPageIndex() >= currentParams->firstPageIndex && segmentIndex >= currentParams->firstSegmentIndex)
|
||||
&& (m_iterator.currentPageIndex() <= currentParams->lastPageIndex && segmentIndex <= currentParams->lastSegmentIndex)) {
|
||||
// prevent making the comment twice if it spreads over multiple pages/segments
|
||||
if (!currentParams->removed
|
||||
&& ((m_iterator.currentPageIndex() == currentParams->firstPageIndex
|
||||
&& m_iterator.currentSegmentIndex() == currentParams->firstSegmentIndex))) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
|
||||
}
|
||||
if (!segmentSize) {
|
||||
++segmentIndex;
|
||||
continue;
|
||||
}
|
||||
// check whether this segment contains the Vorbis Comment
|
||||
if ((m_iterator.currentPageIndex() >= currentParams->firstPageIndex && segmentIndex >= currentParams->firstSegmentIndex)
|
||||
&& (m_iterator.currentPageIndex() <= currentParams->lastPageIndex && segmentIndex <= currentParams->lastSegmentIndex)) {
|
||||
// prevent making the comment twice if it spreads over multiple pages/segments
|
||||
if (!currentParams->removed
|
||||
&& ((m_iterator.currentPageIndex() == currentParams->firstPageIndex
|
||||
&& m_iterator.currentSegmentIndex() == currentParams->firstSegmentIndex))) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
|
||||
}
|
||||
|
||||
// proceed with next comment?
|
||||
if (m_iterator.currentPageIndex() > currentParams->lastPageIndex
|
||||
|| (m_iterator.currentPageIndex() == currentParams->lastPageIndex
|
||||
&& segmentIndex > currentParams->lastSegmentIndex)) {
|
||||
if (++tagIterator != tagEnd) {
|
||||
currentParams = &(currentComment = tagIterator->get())->oggParams();
|
||||
} else {
|
||||
currentComment = nullptr;
|
||||
currentParams = nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy other segments unchanged
|
||||
backupStream.seekg(segmentOffset);
|
||||
copyHelper.copy(backupStream, buffer, segmentSize);
|
||||
newSegmentSizes.push_back(segmentSize);
|
||||
|
||||
// check whether there is a new comment to be inserted into the current page
|
||||
if (m_iterator.currentPageIndex() == currentParams->lastPageIndex
|
||||
&& currentParams->firstSegmentIndex == numeric_limits<size_t>::max()) {
|
||||
if (!currentParams->removed) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
|
||||
}
|
||||
// proceed with next comment
|
||||
if (++tagIterator != tagEnd) {
|
||||
currentParams = &(currentComment = tagIterator->get())->oggParams();
|
||||
} else {
|
||||
currentComment = nullptr;
|
||||
currentParams = nullptr;
|
||||
}
|
||||
// proceed with next comment?
|
||||
if (m_iterator.currentPageIndex() > currentParams->lastPageIndex
|
||||
|| (m_iterator.currentPageIndex() == currentParams->lastPageIndex && segmentIndex > currentParams->lastSegmentIndex)) {
|
||||
if (++tagIterator != tagEnd) {
|
||||
currentParams = &(currentComment = tagIterator->get())->oggParams();
|
||||
} else {
|
||||
currentComment = nullptr;
|
||||
currentParams = nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy other segments unchanged
|
||||
backupStream.seekg(static_cast<streamoff>(segmentOffset));
|
||||
copyHelper.copy(backupStream, buffer, segmentSize);
|
||||
newSegmentSizes.push_back(segmentSize);
|
||||
|
||||
// check whether there is a new comment to be inserted into the current page
|
||||
if (m_iterator.currentPageIndex() == currentParams->lastPageIndex
|
||||
&& currentParams->firstSegmentIndex == numeric_limits<size_t>::max()) {
|
||||
if (!currentParams->removed) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams, diag);
|
||||
}
|
||||
// proceed with next comment
|
||||
if (++tagIterator != tagEnd) {
|
||||
currentParams = &(currentComment = tagIterator->get())->oggParams();
|
||||
} else {
|
||||
currentComment = nullptr;
|
||||
currentParams = nullptr;
|
||||
}
|
||||
}
|
||||
segmentOffset += segmentSize;
|
||||
}
|
||||
segmentOffset += segmentSize;
|
||||
++segmentIndex;
|
||||
}
|
||||
|
||||
|
@ -486,12 +488,12 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
// write pages until all data in the buffer is written
|
||||
while (newSegmentSizesIterator != newSegmentSizesEnd) {
|
||||
// write header
|
||||
backupStream.seekg(currentPage.startOffset());
|
||||
updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
|
||||
backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
|
||||
updatedPageOffsets.push_back(static_cast<uint64>(stream().tellp())); // memorize offset to update checksum later
|
||||
copyHelper.copy(backupStream, stream(), 27); // just copy header from original file
|
||||
// set continue flag
|
||||
stream().seekp(-22, ios_base::cur);
|
||||
stream().put(currentPage.headerTypeFlag() & (continuePreviousSegment ? 0xFF : 0xFE));
|
||||
stream().put(static_cast<char>(currentPage.headerTypeFlag() & (continuePreviousSegment ? 0xFF : 0xFE)));
|
||||
continuePreviousSegment = true;
|
||||
// adjust page sequence number
|
||||
stream().seekp(12, ios_base::cur);
|
||||
|
@ -503,14 +505,14 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
uint32 currentSize = 0;
|
||||
while (bytesLeft && segmentSizesWritten < 0xFF) {
|
||||
while (bytesLeft >= 0xFF && segmentSizesWritten < 0xFF) {
|
||||
stream().put(0xFF);
|
||||
stream().put(static_cast<char>(0xFF));
|
||||
currentSize += 0xFF;
|
||||
bytesLeft -= 0xFF;
|
||||
++segmentSizesWritten;
|
||||
}
|
||||
if (bytesLeft && segmentSizesWritten < 0xFF) {
|
||||
// bytes left is here < 0xFF
|
||||
stream().put(bytesLeft);
|
||||
stream().put(static_cast<char>(bytesLeft));
|
||||
currentSize += bytesLeft;
|
||||
bytesLeft = 0;
|
||||
++segmentSizesWritten;
|
||||
|
@ -534,7 +536,7 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
// -> write segment table size (segmentSizesWritten) and segment data
|
||||
// -> seek back and write updated page segment number
|
||||
stream().seekp(-1 - segmentSizesWritten, ios_base::cur);
|
||||
stream().put(segmentSizesWritten);
|
||||
stream().put(static_cast<char>(segmentSizesWritten));
|
||||
stream().seekp(segmentSizesWritten, ios_base::cur);
|
||||
// -> write actual page data
|
||||
copyHelper.copy(buffer, stream(), currentSize);
|
||||
|
@ -546,8 +548,8 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
} else {
|
||||
if (pageSequenceNumber != m_iterator.currentPageIndex()) {
|
||||
// just update page sequence number
|
||||
backupStream.seekg(currentPage.startOffset());
|
||||
updatedPageOffsets.push_back(stream().tellp()); // memorize offset to update checksum later
|
||||
backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
|
||||
updatedPageOffsets.push_back(static_cast<uint64>(stream().tellp())); // memorize offset to update checksum later
|
||||
copyHelper.copy(backupStream, stream(), 27);
|
||||
stream().seekp(-9, ios_base::cur);
|
||||
writer().writeUInt32LE(pageSequenceNumber);
|
||||
|
@ -555,7 +557,7 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
copyHelper.copy(backupStream, stream(), pageSize - 27);
|
||||
} else {
|
||||
// copy page unchanged
|
||||
backupStream.seekg(currentPage.startOffset());
|
||||
backupStream.seekg(static_cast<streamoff>(currentPage.startOffset()));
|
||||
copyHelper.copy(backupStream, stream(), pageSize);
|
||||
}
|
||||
++pageSequenceNumber;
|
||||
|
@ -563,7 +565,7 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
|||
}
|
||||
|
||||
// report new size
|
||||
fileInfo().reportSizeChanged(stream().tellp());
|
||||
fileInfo().reportSizeChanged(static_cast<uint64>(stream().tellp()));
|
||||
|
||||
// "save as path" is now the regular path
|
||||
if (!fileInfo().saveFilePath().empty()) {
|
||||
|
|
|
@ -136,9 +136,9 @@ void OggIterator::read(char *buffer, size_t count)
|
|||
size_t bytesRead = 0;
|
||||
while (*this && count) {
|
||||
const uint32 available = currentSegmentSize() - m_bytesRead;
|
||||
stream().seekg(currentCharacterOffset());
|
||||
stream().seekg(static_cast<streamoff>(currentCharacterOffset()));
|
||||
if (count <= available) {
|
||||
stream().read(buffer + bytesRead, count);
|
||||
stream().read(buffer + bytesRead, static_cast<streamoff>(count));
|
||||
m_bytesRead += count;
|
||||
return;
|
||||
} else {
|
||||
|
@ -171,9 +171,9 @@ size_t OggIterator::readAll(char *buffer, size_t max)
|
|||
size_t bytesRead = 0;
|
||||
while (*this && max) {
|
||||
const uint32 available = currentSegmentSize() - m_bytesRead;
|
||||
stream().seekg(currentCharacterOffset());
|
||||
stream().seekg(static_cast<streamoff>(currentCharacterOffset()));
|
||||
if (max <= available) {
|
||||
stream().read(buffer + bytesRead, max);
|
||||
stream().read(buffer + bytesRead, static_cast<streamoff>(max));
|
||||
m_bytesRead += max;
|
||||
return bytesRead + max;
|
||||
} else {
|
||||
|
@ -243,7 +243,7 @@ bool OggIterator::resyncAt(uint64 offset)
|
|||
}
|
||||
|
||||
// find capture pattern 'OggS'
|
||||
stream().seekg(offset);
|
||||
stream().seekg(static_cast<streamoff>(offset));
|
||||
byte lettersFound = 0;
|
||||
for (uint64 bytesAvailable = max<uint64>(streamSize() - offset, 65307ul); bytesAvailable >= 27; --bytesAvailable) {
|
||||
switch (static_cast<char>(stream().get())) {
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace TagParser {
|
|||
void OggPage::parseHeader(istream &stream, uint64 startOffset, int32 maxSize)
|
||||
{
|
||||
// prepare reading
|
||||
stream.seekg(startOffset);
|
||||
stream.seekg(static_cast<streamoff>(startOffset));
|
||||
BinaryReader reader(&stream);
|
||||
if (maxSize < 27) {
|
||||
throw TruncatedDataException();
|
||||
|
@ -74,7 +74,7 @@ void OggPage::parseHeader(istream &stream, uint64 startOffset, int32 maxSize)
|
|||
*/
|
||||
uint32 OggPage::computeChecksum(istream &stream, uint64 startOffset)
|
||||
{
|
||||
stream.seekg(startOffset);
|
||||
stream.seekg(static_cast<streamoff>(startOffset));
|
||||
uint32 crc = 0x0;
|
||||
byte value, segmentTableSize = 0, segmentTableIndex = 0;
|
||||
for (uint32 i = 0, segmentLength = 27; i != segmentLength; ++i) {
|
||||
|
@ -82,6 +82,7 @@ uint32 OggPage::computeChecksum(istream &stream, uint64 startOffset)
|
|||
case 22:
|
||||
// bytes 22, 23, 24, 25 hold denoted checksum and must be set to zero
|
||||
stream.seekg(4, ios_base::cur);
|
||||
FALLTHROUGH;
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
|
@ -89,10 +90,10 @@ uint32 OggPage::computeChecksum(istream &stream, uint64 startOffset)
|
|||
break;
|
||||
case 26:
|
||||
// byte 26 holds the number of segment sizes
|
||||
segmentLength += (segmentTableSize = (value = stream.get()));
|
||||
segmentLength += (segmentTableSize = (value = static_cast<byte>(stream.get())));
|
||||
break;
|
||||
default:
|
||||
value = stream.get();
|
||||
value = static_cast<byte>(stream.get());
|
||||
if (i > 26 && segmentTableIndex < segmentTableSize) {
|
||||
// bytes 27 to (27 + segment size count) hold page size
|
||||
segmentLength += value;
|
||||
|
@ -112,7 +113,7 @@ void OggPage::updateChecksum(iostream &stream, uint64 startOffset)
|
|||
{
|
||||
char buff[4];
|
||||
LE::getBytes(computeChecksum(stream, startOffset), buff);
|
||||
stream.seekp(startOffset + 22);
|
||||
stream.seekp(static_cast<streamoff>(startOffset + 22));
|
||||
stream.write(buff, sizeof(buff));
|
||||
}
|
||||
|
||||
|
@ -124,11 +125,11 @@ uint32 OggPage::makeSegmentSizeDenotation(ostream &stream, uint32 size)
|
|||
{
|
||||
uint32 bytesWritten = 1;
|
||||
while (size >= 0xff) {
|
||||
stream.put(0xff);
|
||||
stream.put(static_cast<char>(0xff));
|
||||
size -= 0xff;
|
||||
++bytesWritten;
|
||||
}
|
||||
stream.put(size);
|
||||
stream.put(static_cast<char>(size));
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ void OggStream::internalParseHeader(Diagnostics &diag)
|
|||
const uint32 currentSize = iterator.currentSegmentSize();
|
||||
if (currentSize >= 8) {
|
||||
// determine stream format
|
||||
inputStream().seekg(iterator.currentSegmentOffset());
|
||||
inputStream().seekg(static_cast<streamoff>(iterator.currentSegmentOffset()));
|
||||
const uint64 sig = reader().readUInt64BE();
|
||||
|
||||
if ((sig & 0x00ffffffffffff00u) == 0x00766F7262697300u) {
|
||||
|
|
31
tagvalue.cpp
31
tagvalue.cpp
|
@ -77,21 +77,22 @@ TagValue::TagValue(const TagValue &other)
|
|||
*/
|
||||
TagValue &TagValue::operator=(const TagValue &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_size = other.m_size;
|
||||
m_type = other.m_type;
|
||||
m_desc = other.m_desc;
|
||||
m_mimeType = other.m_mimeType;
|
||||
m_language = other.m_language;
|
||||
m_labeledAsReadonly = other.m_labeledAsReadonly;
|
||||
m_encoding = other.m_encoding;
|
||||
m_descEncoding = other.m_descEncoding;
|
||||
if (other.isEmpty()) {
|
||||
m_ptr.reset();
|
||||
} else {
|
||||
m_ptr = make_unique<char[]>(m_size);
|
||||
std::copy(other.m_ptr.get(), other.m_ptr.get() + other.m_size, m_ptr.get());
|
||||
}
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
m_type = other.m_type;
|
||||
m_desc = other.m_desc;
|
||||
m_mimeType = other.m_mimeType;
|
||||
m_language = other.m_language;
|
||||
m_labeledAsReadonly = other.m_labeledAsReadonly;
|
||||
m_encoding = other.m_encoding;
|
||||
m_descEncoding = other.m_descEncoding;
|
||||
if (other.isEmpty()) {
|
||||
m_ptr.reset();
|
||||
} else {
|
||||
m_ptr = make_unique<char[]>(m_size);
|
||||
std::copy(other.m_ptr.get(), other.m_ptr.get() + other.m_size, m_ptr.get());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -396,7 +396,7 @@ inline void TagValue::clearDataAndMetadata()
|
|||
* \brief Returns the size of the assigned value in bytes.
|
||||
* \remarks Meta data such as description and MIME type is not considered as part of the assigned value.
|
||||
*/
|
||||
inline size_t TagValue::dataSize() const
|
||||
inline std::size_t TagValue::dataSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
|
|
@ -191,6 +191,9 @@ bool VorbisCommentField::make(BinaryWriter &writer, VorbisCommentFlags flags, Di
|
|||
|
||||
pictureBlock.make(bufferStream);
|
||||
valueString = encodeBase64(reinterpret_cast<byte *>(buffer.get()), requiredSize);
|
||||
} catch (const Failure &) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to make METADATA_BLOCK_PICTURE struct from the assigned value.", context);
|
||||
throw;
|
||||
} catch (...) {
|
||||
catchIoFailure();
|
||||
diag.emplace_back(DiagLevel::Critical, "An IO error occured when writing the METADATA_BLOCK_PICTURE struct.", context);
|
||||
|
@ -200,7 +203,12 @@ bool VorbisCommentField::make(BinaryWriter &writer, VorbisCommentFlags flags, Di
|
|||
// make normal string value
|
||||
valueString = value().toString();
|
||||
}
|
||||
writer.writeUInt32LE(id().size() + 1 + valueString.size());
|
||||
const auto size(valueString.size() + id().size() + 1);
|
||||
if (size > numeric_limits<uint32>::max()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Assigned value exceeds the maximum size.", context);
|
||||
throw InvalidDataException();
|
||||
}
|
||||
writer.writeUInt32LE(static_cast<uint32>(size));
|
||||
writer.writeString(id());
|
||||
writer.writeChar('=');
|
||||
writer.writeString(valueString);
|
||||
|
|
|
@ -114,7 +114,7 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
|||
if (m_reader.readUInt32BE() != 0x52494646u) {
|
||||
throw NoDataFoundException();
|
||||
}
|
||||
m_istream->seekg(m_startOffset + 8);
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset + 8));
|
||||
if (m_reader.readUInt32BE() != 0x57415645u) {
|
||||
throw NoDataFoundException();
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
|||
}
|
||||
break;
|
||||
case 0x64617461u:
|
||||
m_dataOffset = m_istream->tellg();
|
||||
m_dataOffset = static_cast<uint64>(m_istream->tellg());
|
||||
m_size = restHeaderLen;
|
||||
m_sampleCount = m_size / m_chunkSize;
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
|
||||
|
@ -145,7 +145,7 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
|||
if (m_format.general != GeneralMediaFormat::Mpeg1Audio || !m_dataOffset) {
|
||||
return;
|
||||
}
|
||||
m_istream->seekg(m_dataOffset);
|
||||
m_istream->seekg(static_cast<streamoff>(m_dataOffset));
|
||||
MpegAudioFrame frame;
|
||||
frame.parseHeader(m_reader);
|
||||
MpegAudioFrameStream::addInfo(frame, *this);
|
||||
|
@ -153,7 +153,7 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
|||
? ((static_cast<double>(m_size) * 8.0)
|
||||
/ (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
|
||||
: frame.bitrate();
|
||||
m_bytesPerSecond = m_bitrate * 125;
|
||||
m_bytesPerSecond = static_cast<uint32>(m_bitrate * 125);
|
||||
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue