Matroska: Fix build with older macOS and 32-bit Android compilers

When building for macOS < 10.14, the API for std::optional and
std::variant is restricted

    error: 'value' is unavailable: introduced in macOS 10.14
    error: 'get<..>' is unavailable: introduced in macOS 10.14

There was also an issue with Android armeabi-v7a where long is not
64 bit and a static assertion failed.
This commit is contained in:
Urs Fleisch
2026-01-02 15:30:41 +01:00
parent f4e7a742c3
commit d83d751443
6 changed files with 40 additions and 43 deletions

View File

@ -52,7 +52,7 @@ std::unique_ptr<EBML::Element> EBML::Element::factory(File &file)
}
// Get the size length and data length
const auto &[sizeLength, dataSize] = readVINT<offset_t>(file);
const auto &[sizeLength, dataSize] = readVINT(file);
if(!sizeLength)
return nullptr;

View File

@ -52,10 +52,12 @@ EBML::FloatElement::FloatVariantType EBML::FloatElement::getValue() const
double EBML::FloatElement::getValueAsDouble(double defaultValue) const
{
if(std::holds_alternative<double>(value)) {
return std::get<double>(value);
// get_if() used instead of get() to support restricted compilers
return *std::get_if<double>(&value);
}
if(std::holds_alternative<float>(value)) {
return std::get<float>(value);
// get_if() used instead of get() to support restricted compilers
return *std::get_if<float>(&value);
}
return defaultValue;
}
@ -93,10 +95,12 @@ ByteVector EBML::FloatElement::render()
{
ByteVector data;
if(std::holds_alternative<double>(value)) {
data = ByteVector::fromFloat64BE(std::get<double>(value));
// get_if() used instead of get() to support restricted compilers
data = ByteVector::fromFloat64BE(*std::get_if<double>(&value));
}
else if(std::holds_alternative<float>(value)) {
data = ByteVector::fromFloat32BE(std::get<float>(value));
// get_if() used instead of get() to support restricted compilers
data = ByteVector::fromFloat32BE(*std::get_if<float>(&value));
}
ByteVector buffer = renderId();
buffer.append(renderVINT(data.size(), 0));

View File

@ -71,33 +71,25 @@ namespace TagLib::EBML {
template unsigned int VINTSizeLength<8>(uint8_t firstByte);
}
template <typename T>
std::pair<int, T> EBML::readVINT(File &file)
std::pair<unsigned int, uint64_t> EBML::readVINT(File &file)
{
static_assert(sizeof(T) == 8);
auto buffer = file.readBlock(1);
if(buffer.size() != 1) {
debug("Failed to read VINT size");
return {0, 0};
}
unsigned int nb_bytes = VINTSizeLength<8>(*buffer.begin());
if(!nb_bytes)
unsigned int numBytes = VINTSizeLength<8>(*buffer.begin());
if(!numBytes)
return {0, 0};
if(nb_bytes > 1)
buffer.append(file.readBlock(nb_bytes - 1));
const int bitsToShift = static_cast<int>(sizeof(T) * 8) - 7 * nb_bytes;
offset_t mask = 0xFFFFFFFFFFFFFFFF >> bitsToShift;
return { nb_bytes, static_cast<T>(buffer.toLongLong(true)) & mask };
if(numBytes > 1)
buffer.append(file.readBlock(numBytes - 1));
const int bitsToShift = static_cast<int>(sizeof(uint64_t) * 8) - 7 * numBytes;
const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> bitsToShift;
return { numBytes, buffer.toULongLong(true) & mask };
}
namespace TagLib::EBML {
template std::pair<int, offset_t> readVINT<offset_t>(File &file);
template std::pair<int, uint64_t> readVINT<uint64_t>(File &file);
}
template <typename T>
std::pair<int, T> EBML::parseVINT(const ByteVector &buffer)
std::pair<unsigned int, uint64_t> EBML::parseVINT(const ByteVector &buffer)
{
if(buffer.isEmpty())
return {0, 0};
@ -106,14 +98,9 @@ std::pair<int, T> EBML::parseVINT(const ByteVector &buffer)
if(!numBytes)
return {0, 0};
const int bitsToShift = static_cast<int>(sizeof(T) * 8) - 7 * numBytes;
offset_t mask = 0xFFFFFFFFFFFFFFFF >> bitsToShift;
return { numBytes, static_cast<T>(buffer.toLongLong(true)) & mask };
}
namespace TagLib::EBML {
template std::pair<int, offset_t> parseVINT<offset_t>(const ByteVector &buffer);
template std::pair<int, uint64_t> parseVINT<uint64_t>(const ByteVector &buffer);
const int bitsToShift = static_cast<int>(sizeof(uint64_t) * 8) - 7 * numBytes;
const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> bitsToShift;
return { numBytes, buffer.toULongLong(true) & mask };
}
ByteVector EBML::renderVINT(uint64_t number, int minSizeLength)

View File

@ -37,11 +37,9 @@ namespace TagLib {
template <int maxSizeLength>
unsigned int VINTSizeLength(uint8_t firstByte);
template <typename T>
std::pair<int, T> readVINT(File &file);
std::pair<unsigned int, uint64_t> readVINT(File &file);
template <typename T>
std::pair<int, T> parseVINT(const ByteVector &buffer);
std::pair<unsigned int, uint64_t> parseVINT(const ByteVector &buffer);
ByteVector renderVINT(uint64_t number, int minSizeLength);

View File

@ -66,28 +66,32 @@ ByteVector Matroska::Cues::renderInternal()
// Relative position, optional
if(cueTrack->getRelativePosition().has_value()) {
auto relativePosition = EBML::make_unique_element<EBML::Element::Id::MkCueRelativePosition>();
relativePosition->setValue(cueTrack->getRelativePosition().value());
// operator*() used instead of value() to support restricted compilers
relativePosition->setValue(*cueTrack->getRelativePosition());
cueTrackElement->appendElement(std::move(relativePosition));
}
// Duration, optional
if(cueTrack->getDuration().has_value()) {
auto duration = EBML::make_unique_element<EBML::Element::Id::MkCueDuration>();
duration->setValue(cueTrack->getDuration().value());
// operator*() used instead of value() to support restricted compilers
duration->setValue(*cueTrack->getDuration());
cueTrackElement->appendElement(std::move(duration));
}
// Block number, optional
if(cueTrack->getBlockNumber().has_value()) {
auto blockNumber = EBML::make_unique_element<EBML::Element::Id::MkCueBlockNumber>();
blockNumber->setValue(cueTrack->getBlockNumber().value());
// operator*() used instead of value() to support restricted compilers
blockNumber->setValue(*cueTrack->getBlockNumber());
cueTrackElement->appendElement(std::move(blockNumber));
}
// Codec state, not in version 1
if(cueTrack->getCodecState().has_value()) {
auto codecState = EBML::make_unique_element<EBML::Element::Id::MkCueCodecState>();
codecState->setValue(cueTrack->getCodecState().value());
// operator*() used instead of value() to support restricted compilers
codecState->setValue(*cueTrack->getCodecState());
cueTrackElement->appendElement(std::move(codecState));
}
@ -209,8 +213,9 @@ bool Matroska::CueTrack::isValid(TagLib::File &file, offset_t segmentDataOffset)
debug("No cluster found at position");
return false;
}
if(codecState.has_value() && codecState.value() != 0) {
file.seek(segmentDataOffset + codecState.value());
if(codecState.has_value() && *codecState != 0) {
// operator*() used instead of value() to support restricted compilers
file.seek(segmentDataOffset + *codecState);
if(EBML::Element::readId(file) != static_cast<unsigned int>(EBML::Element::Id::MkCodecState)) {
debug("No codec state found at position");
return false;
@ -296,8 +301,9 @@ bool Matroska::CueTrack::adjustOffset(offset_t offset, offset_t delta)
clusterPosition += delta;
ret = true;
}
// operator*() used instead of value() to support restricted compilers
if(offset_t codecStateValue;
codecState.has_value() && (codecStateValue = codecState.value()) != 0 &&
codecState.has_value() && (codecStateValue = *codecState) != 0 &&
codecStateValue > offset) {
codecState = codecStateValue + delta;
ret = true;

View File

@ -126,7 +126,8 @@ Matroska::SimpleTag::ValueType Matroska::SimpleTag::type() const
String Matroska::SimpleTag::toString() const
{
if(std::holds_alternative<String>(d->value)) {
return std::get<String>(d->value);
// get_if() used instead of get() to support restricted compilers
return *std::get_if<String>(&d->value);
}
return {};
}
@ -134,7 +135,8 @@ String Matroska::SimpleTag::toString() const
ByteVector Matroska::SimpleTag::toByteVector() const
{
if(std::holds_alternative<ByteVector>(d->value)) {
return std::get<ByteVector>(d->value);
// get_if() used instead of get() to support restricted compilers
return *std::get_if<ByteVector>(&d->value);
}
return {};
}