mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-26 19:26:59 +03:00
Prevent Digest32 shared data from being detached
Delayed hash string generation should not cause detaching of shared data. PR #16664.
This commit is contained in:
parent
5960e7dda6
commit
ca2be2f499
1 changed files with 59 additions and 33 deletions
|
@ -48,10 +48,8 @@ public:
|
||||||
Digest32(Digest32 &&other) = default;
|
Digest32(Digest32 &&other) = default;
|
||||||
|
|
||||||
Digest32(const UnderlyingType &nativeDigest)
|
Digest32(const UnderlyingType &nativeDigest)
|
||||||
|
: m_dataPtr {new Data(nativeDigest)}
|
||||||
{
|
{
|
||||||
m_dataPtr->valid = true;
|
|
||||||
m_dataPtr->nativeDigest = nativeDigest;
|
|
||||||
m_dataPtr->hashString.clear(); // hashString is created on demand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int length()
|
static constexpr int length()
|
||||||
|
@ -61,7 +59,7 @@ public:
|
||||||
|
|
||||||
bool isValid() const
|
bool isValid() const
|
||||||
{
|
{
|
||||||
return m_dataPtr->valid;
|
return m_dataPtr->isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
Digest32 &operator=(const Digest32 &other) = default;
|
Digest32 &operator=(const Digest32 &other) = default;
|
||||||
|
@ -69,48 +67,76 @@ public:
|
||||||
|
|
||||||
operator UnderlyingType() const
|
operator UnderlyingType() const
|
||||||
{
|
{
|
||||||
return m_dataPtr->nativeDigest;
|
return m_dataPtr->nativeDigest();
|
||||||
}
|
|
||||||
|
|
||||||
static Digest32 fromString(const QString &digestString)
|
|
||||||
{
|
|
||||||
if (digestString.size() != (length() * 2))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const QByteArray raw = QByteArray::fromHex(digestString.toLatin1());
|
|
||||||
if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters
|
|
||||||
return {};
|
|
||||||
|
|
||||||
Digest32 result;
|
|
||||||
result.m_dataPtr->valid = true;
|
|
||||||
result.m_dataPtr->hashString = digestString;
|
|
||||||
result.m_dataPtr->nativeDigest.assign(raw.constData());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString toString() const
|
QString toString() const
|
||||||
{
|
{
|
||||||
if (m_dataPtr->hashString.isEmpty())
|
return m_dataPtr->hashString();
|
||||||
{
|
}
|
||||||
const QByteArray raw = QByteArray::fromRawData(m_dataPtr->nativeDigest.data(), length());
|
|
||||||
const_cast<Digest32 *>(this)->m_dataPtr->hashString = QString::fromLatin1(raw.toHex());
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_dataPtr->hashString;
|
static Digest32 fromString(const QString &digestString)
|
||||||
|
{
|
||||||
|
return Digest32(QSharedDataPointer<Data>(new Data(digestString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Data : public QSharedData
|
class Data;
|
||||||
|
|
||||||
|
explicit Digest32(QSharedDataPointer<Data> dataPtr)
|
||||||
|
: m_dataPtr {dataPtr}
|
||||||
{
|
{
|
||||||
bool valid = false;
|
}
|
||||||
UnderlyingType nativeDigest;
|
|
||||||
QString hashString;
|
|
||||||
};
|
|
||||||
|
|
||||||
QSharedDataPointer<Data> m_dataPtr {new Data};
|
QSharedDataPointer<Data> m_dataPtr {new Data};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class Digest32<N>::Data : public QSharedData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Data() = default;
|
||||||
|
|
||||||
|
explicit Data(UnderlyingType nativeDigest)
|
||||||
|
: m_isValid {true}
|
||||||
|
, m_nativeDigest {nativeDigest}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Data(const QString &digestString)
|
||||||
|
{
|
||||||
|
if (digestString.size() != (length() * 2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QByteArray raw = QByteArray::fromHex(digestString.toLatin1());
|
||||||
|
if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_isValid = true;
|
||||||
|
m_hashString = digestString;
|
||||||
|
m_nativeDigest.assign(raw.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const { return m_isValid; }
|
||||||
|
UnderlyingType nativeDigest() const { return m_nativeDigest; }
|
||||||
|
|
||||||
|
QString hashString() const
|
||||||
|
{
|
||||||
|
if (m_hashString.isEmpty())
|
||||||
|
{
|
||||||
|
const QByteArray raw = QByteArray::fromRawData(m_nativeDigest.data(), length());
|
||||||
|
m_hashString = QString::fromLatin1(raw.toHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_hashString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isValid = false;
|
||||||
|
UnderlyingType m_nativeDigest;
|
||||||
|
mutable QString m_hashString;
|
||||||
|
};
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
bool operator==(const Digest32<N> &left, const Digest32<N> &right)
|
bool operator==(const Digest32<N> &left, const Digest32<N> &right)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue