mirror of https://github.com/procxx/kepka.git
Add general StorageFileLocation abstraction.
This commit is contained in:
parent
d36f6a0322
commit
eba2a98703
|
@ -43,13 +43,6 @@ inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
|
|||
return MediaKey(mediaMix32To64(type, dc), id);
|
||||
}
|
||||
|
||||
inline StorageKey mediaKey(const MTPDfileLocation &location) {
|
||||
return storageKey(
|
||||
location.vdc_id.v,
|
||||
location.vvolume_id.v,
|
||||
location.vlocal_id.v);
|
||||
}
|
||||
|
||||
struct DocumentAdditionalData {
|
||||
virtual ~DocumentAdditionalData() = default;
|
||||
|
||||
|
|
|
@ -247,19 +247,19 @@ bool PeerData::userpicLoaded() const {
|
|||
}
|
||||
|
||||
bool PeerData::useEmptyUserpic() const {
|
||||
return _userpicLocation.isNull()
|
||||
return !_userpicLocation.valid()
|
||||
|| !_userpic
|
||||
|| !_userpic->loaded();
|
||||
}
|
||||
|
||||
StorageKey PeerData::userpicUniqueKey() const {
|
||||
InMemoryKey PeerData::userpicUniqueKey() const {
|
||||
if (useEmptyUserpic()) {
|
||||
if (!_userpicEmpty) {
|
||||
refreshEmptyUserpic();
|
||||
}
|
||||
return _userpicEmpty->uniqueKey();
|
||||
}
|
||||
return storageKey(_userpicLocation);
|
||||
return inMemoryKey(_userpicLocation);
|
||||
}
|
||||
|
||||
void PeerData::saveUserpic(const QString &path, int size) const {
|
||||
|
|
|
@ -234,7 +234,7 @@ public:
|
|||
void loadUserpic(bool loadFirst = false, bool prior = true);
|
||||
[[nodiscard]] bool userpicLoaded() const;
|
||||
[[nodiscard]] bool useEmptyUserpic() const;
|
||||
[[nodiscard]] StorageKey userpicUniqueKey() const;
|
||||
[[nodiscard]] InMemoryKey userpicUniqueKey() const;
|
||||
void saveUserpic(const QString &path, int size) const;
|
||||
void saveUserpicRounded(const QString &path, int size) const;
|
||||
[[nodiscard]] QPixmap genUserpic(int size) const;
|
||||
|
|
|
@ -53,7 +53,11 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
|
|||
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||
result.id = data.vvolume_id.v;
|
||||
}, [&](const MTPDinputDocumentFileLocation &data) {
|
||||
const auto letter = data.vthumb_size.v.isEmpty()
|
||||
? char(0)
|
||||
: data.vthumb_size.v[0];
|
||||
result.type |= (2ULL << 24);
|
||||
result.type |= (uint64(uint32(letter)) << 16);
|
||||
result.id = data.vid.v;
|
||||
}, [&](const MTPDinputSecureFileLocation &data) {
|
||||
result.type |= (3ULL << 24);
|
||||
|
@ -63,6 +67,23 @@ LocationKey ComputeLocationKey(const Data::FileLocation &value) {
|
|||
result.id = data.vid.v;
|
||||
}, [&](const MTPDinputTakeoutFileLocation &data) {
|
||||
result.type |= (5ULL << 24);
|
||||
}, [&](const MTPDinputPhotoFileLocation &data) {
|
||||
const auto letter = data.vthumb_size.v.isEmpty()
|
||||
? char(0)
|
||||
: data.vthumb_size.v[0];
|
||||
result.type |= (6ULL << 24);
|
||||
result.type |= (uint64(uint32(letter)) << 16);
|
||||
result.id = data.vid.v;
|
||||
}, [&](const MTPDinputPeerPhotoFileLocation &data) {
|
||||
const auto letter = data.is_big() ? char(1) : char(0);
|
||||
result.type |= (7ULL << 24);
|
||||
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||
result.type |= (uint64(uint32(letter)) << 16);
|
||||
result.id = data.vvolume_id.v;
|
||||
}, [&](const MTPDinputStickerSetThumb &data) {
|
||||
result.type |= (8ULL << 24);
|
||||
result.type |= (uint64(uint32(data.vlocal_id.v)) << 32);
|
||||
result.id = data.vvolume_id.v;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -440,12 +440,9 @@ void Manager::Private::showNextNotification() {
|
|||
return;
|
||||
}
|
||||
|
||||
StorageKey key;
|
||||
if (data.hideNameAndPhoto) {
|
||||
key = StorageKey(0, 0);
|
||||
} else {
|
||||
key = data.peer->userpicUniqueKey();
|
||||
}
|
||||
const auto key = data.hideNameAndPhoto
|
||||
? InMemoryKey()
|
||||
: data.peer->userpicUniqueKey();
|
||||
notification->setImage(_cachedUserpics.get(key, data.peer));
|
||||
|
||||
auto i = _notifications.find(peerId);
|
||||
|
|
|
@ -459,14 +459,11 @@ bool Manager::Private::showNotification(PeerData *peer, MsgId msgId, const QStri
|
|||
hr = SetAudioSilent(toastXml.Get());
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
||||
StorageKey key;
|
||||
if (hideNameAndPhoto) {
|
||||
key = StorageKey(0, 0);
|
||||
} else {
|
||||
key = peer->userpicUniqueKey();
|
||||
}
|
||||
auto userpicPath = _cachedUserpics.get(key, peer);
|
||||
auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
||||
const auto key = hideNameAndPhoto
|
||||
? InMemoryKey()
|
||||
: peer->userpicUniqueKey();
|
||||
const auto userpicPath = _cachedUserpics.get(key, peer);
|
||||
const auto userpicPathWide = QDir::toNativeSeparators(userpicPath).toStdWString();
|
||||
|
||||
hr = SetImageSrc(userpicPathWide.c_str(), toastXml.Get());
|
||||
if (!SUCCEEDED(hr)) return false;
|
||||
|
|
|
@ -508,10 +508,10 @@ enum { // Local Storage Keys
|
|||
lskUserMap = 0x00,
|
||||
lskDraft = 0x01, // data: PeerId peer
|
||||
lskDraftPosition = 0x02, // data: PeerId peer
|
||||
lskImages = 0x03, // data: StorageKey location
|
||||
lskLegacyImages = 0x03, // legacy
|
||||
lskLocations = 0x04, // no data
|
||||
lskStickerImages = 0x05, // data: StorageKey location
|
||||
lskAudios = 0x06, // data: StorageKey location
|
||||
lskLegacyStickerImages = 0x05, // legacy
|
||||
lskLegacyAudios = 0x06, // legacy
|
||||
lskRecentStickersOld = 0x07, // no data
|
||||
lskBackgroundOld = 0x08, // no data
|
||||
lskUserSettings = 0x09, // no data
|
||||
|
@ -2332,9 +2332,9 @@ ReadMapState _readMap(const QByteArray &pass) {
|
|||
draftCursorsMap.insert(p, key);
|
||||
}
|
||||
} break;
|
||||
case lskImages:
|
||||
case lskStickerImages:
|
||||
case lskAudios: {
|
||||
case lskLegacyImages:
|
||||
case lskLegacyStickerImages:
|
||||
case lskLegacyAudios: {
|
||||
quint32 count = 0;
|
||||
map.stream >> count;
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
|
@ -3188,30 +3188,6 @@ FileLocation readFileLocation(MediaKey location, bool check) {
|
|||
return FileLocation();
|
||||
}
|
||||
|
||||
qint32 _storageImageSize(qint32 rawlen) {
|
||||
// fulllen + storagekey + type + len + data
|
||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + rawlen;
|
||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
||||
return result;
|
||||
}
|
||||
|
||||
qint32 _storageStickerSize(qint32 rawlen) {
|
||||
// fulllen + storagekey + len + data
|
||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
|
||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
||||
return result;
|
||||
}
|
||||
|
||||
qint32 _storageAudioSize(qint32 rawlen) {
|
||||
// fulllen + storagekey + len + data
|
||||
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
|
||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
||||
return result;
|
||||
}
|
||||
|
||||
Storage::EncryptionKey cacheKey() {
|
||||
Expects(LocalKey != nullptr);
|
||||
|
||||
|
|
|
@ -160,11 +160,12 @@ void EmptyUserpic::PaintSavedMessages(
|
|||
}
|
||||
}
|
||||
|
||||
StorageKey EmptyUserpic::uniqueKey() const {
|
||||
auto first = 0xFFFFFFFF00000000ULL | anim::getPremultiplied(_color->c);
|
||||
InMemoryKey EmptyUserpic::uniqueKey() const {
|
||||
const auto first = (uint64(0xFFFFFFFFU) << 32)
|
||||
| anim::getPremultiplied(_color->c);
|
||||
auto second = uint64(0);
|
||||
memcpy(&second, _string.constData(), qMin(sizeof(second), _string.size() * sizeof(QChar)));
|
||||
return StorageKey(first, second);
|
||||
return InMemoryKey(first, second);
|
||||
}
|
||||
|
||||
QPixmap EmptyUserpic::generate(int size) {
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
int outerWidth,
|
||||
int size) const;
|
||||
QPixmap generate(int size);
|
||||
StorageKey uniqueKey() const;
|
||||
InMemoryKey uniqueKey() const;
|
||||
|
||||
static void PaintSavedMessages(
|
||||
Painter &p,
|
||||
|
|
|
@ -22,11 +22,11 @@ namespace {
|
|||
// After 128 MB of unpacked images we try to clear some memory.
|
||||
constexpr auto kMemoryForCache = 128 * 1024 * 1024;
|
||||
|
||||
QMap<QString, Image*> LocalFileImages;
|
||||
QMap<QString, Image*> WebUrlImages;
|
||||
QMap<StorageKey, Image*> StorageImages;
|
||||
QMap<StorageKey, Image*> WebCachedImages;
|
||||
QMap<StorageKey, Image*> GeoPointImages;
|
||||
std::map<QString, std::unique_ptr<Image>> LocalFileImages;
|
||||
std::map<QString, std::unique_ptr<Image>> WebUrlImages;
|
||||
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> StorageImages;
|
||||
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> WebCachedImages;
|
||||
std::unordered_map<InMemoryKey, std::unique_ptr<Image>> GeoPointImages;
|
||||
|
||||
int64 ComputeUsage(QSize size) {
|
||||
return int64(size.width()) * size.height() * 4;
|
||||
|
@ -60,25 +60,15 @@ uint64 SinglePixKey(Options options) {
|
|||
} // namespace
|
||||
|
||||
void ClearRemote() {
|
||||
for (auto image : base::take(StorageImages)) {
|
||||
delete image;
|
||||
}
|
||||
for (auto image : base::take(WebUrlImages)) {
|
||||
delete image;
|
||||
}
|
||||
for (auto image : base::take(WebCachedImages)) {
|
||||
delete image;
|
||||
}
|
||||
for (auto image : base::take(GeoPointImages)) {
|
||||
delete image;
|
||||
}
|
||||
base::take(StorageImages);
|
||||
base::take(WebUrlImages);
|
||||
base::take(WebCachedImages);
|
||||
base::take(GeoPointImages);
|
||||
}
|
||||
|
||||
void ClearAll() {
|
||||
ActiveCache().clear();
|
||||
for (auto image : base::take(LocalFileImages)) {
|
||||
delete image;
|
||||
}
|
||||
base::take(LocalFileImages);
|
||||
ClearRemote();
|
||||
}
|
||||
|
||||
|
@ -86,54 +76,61 @@ ImagePtr Create(const QString &file, QByteArray format) {
|
|||
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|
||||
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
||||
const auto &key = file;
|
||||
auto i = WebUrlImages.constFind(key);
|
||||
if (i == WebUrlImages.cend()) {
|
||||
i = WebUrlImages.insert(
|
||||
const auto i = WebUrlImages.find(key);
|
||||
const auto image = (i != end(WebUrlImages))
|
||||
? i->second.get()
|
||||
: WebUrlImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<WebUrlSource>(file)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
} else {
|
||||
QFileInfo f(file);
|
||||
const auto key = qsl("//:%1//:%2//:"
|
||||
).arg(f.size()
|
||||
).arg(f.lastModified().toTime_t()
|
||||
) + file;
|
||||
auto i = LocalFileImages.constFind(key);
|
||||
if (i == LocalFileImages.cend()) {
|
||||
i = LocalFileImages.insert(
|
||||
key,
|
||||
new Image(std::make_unique<LocalFileSource>(
|
||||
std::make_unique<Image>(std::make_unique<WebUrlSource>(file))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
QFileInfo f(file);
|
||||
const auto key = qsl("//:%1//:%2//:"
|
||||
).arg(f.size()
|
||||
).arg(f.lastModified().toTime_t()
|
||||
) + file;
|
||||
const auto i = LocalFileImages.find(key);
|
||||
const auto image = (i != end(LocalFileImages))
|
||||
? i->second.get()
|
||||
: LocalFileImages.emplace(
|
||||
key,
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<LocalFileSource>(
|
||||
file,
|
||||
QByteArray(),
|
||||
format)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
}
|
||||
format))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(const QString &url, QSize box) {
|
||||
const auto key = qsl("//:%1//:%2//:").arg(box.width()).arg(box.height()) + url;
|
||||
auto i = WebUrlImages.constFind(key);
|
||||
if (i == WebUrlImages.cend()) {
|
||||
i = WebUrlImages.insert(
|
||||
const auto i = WebUrlImages.find(key);
|
||||
const auto image = (i != end(WebUrlImages))
|
||||
? i->second.get()
|
||||
: WebUrlImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<WebUrlSource>(url, box)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
std::make_unique<Image>(std::make_unique<WebUrlSource>(url, box))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(const QString &url, int width, int height) {
|
||||
const auto key = url;
|
||||
auto i = WebUrlImages.constFind(key);
|
||||
if (i == WebUrlImages.cend()) {
|
||||
i = WebUrlImages.insert(
|
||||
const auto &key = url;
|
||||
const auto i = WebUrlImages.find(key);
|
||||
const auto found = (i != end(WebUrlImages));
|
||||
const auto image = found
|
||||
? i->second.get()
|
||||
: WebUrlImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<WebUrlSource>(url, width, height)));
|
||||
} else {
|
||||
i.value()->setInformation(0, width, height);
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<WebUrlSource>(url, width, height))
|
||||
).first->second.get();
|
||||
if (found) {
|
||||
image->setInformation(0, width, height);
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(const QByteArray &filecontent, QByteArray format) {
|
||||
|
@ -165,34 +162,40 @@ ImagePtr Create(int width, int height) {
|
|||
}
|
||||
|
||||
ImagePtr Create(const StorageImageLocation &location, int size) {
|
||||
const auto key = storageKey(location);
|
||||
auto i = StorageImages.constFind(key);
|
||||
if (i == StorageImages.cend()) {
|
||||
i = StorageImages.insert(
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = StorageImages.find(key);
|
||||
const auto found = (i != end(StorageImages));
|
||||
const auto image = found
|
||||
? i->second.get()
|
||||
: StorageImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<StorageSource>(location, size)));
|
||||
} else {
|
||||
i.value()->refreshFileReference(location.fileReference());
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<StorageSource>(location, size))
|
||||
).first->second.get();
|
||||
if (found) {
|
||||
image->refreshFileReference(location.fileReference());
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(
|
||||
const StorageImageLocation &location,
|
||||
const QByteArray &bytes) {
|
||||
const auto key = storageKey(location);
|
||||
auto i = StorageImages.constFind(key);
|
||||
if (i == StorageImages.cend()) {
|
||||
i = StorageImages.insert(
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = StorageImages.find(key);
|
||||
const auto found = (i != end(StorageImages));
|
||||
const auto image = found
|
||||
? i->second.get()
|
||||
: StorageImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<StorageSource>(
|
||||
location,
|
||||
bytes.size())));
|
||||
} else {
|
||||
i.value()->refreshFileReference(location.fileReference());
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<StorageSource>(location, bytes.size()))
|
||||
).first->second.get();
|
||||
if (found) {
|
||||
image->refreshFileReference(location.fileReference());
|
||||
}
|
||||
i.value()->setImageBytes(bytes);
|
||||
return ImagePtr(i.value());
|
||||
image->setImageBytes(bytes);
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) {
|
||||
|
@ -284,17 +287,18 @@ ImagePtr Create(
|
|||
const WebFileLocation &location,
|
||||
QSize box,
|
||||
int size) {
|
||||
const auto key = storageKey(location);
|
||||
auto i = WebCachedImages.constFind(key);
|
||||
if (i == WebCachedImages.cend()) {
|
||||
i = WebCachedImages.insert(
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = WebCachedImages.find(key);
|
||||
const auto image = (i != end(WebCachedImages))
|
||||
? i->second.get()
|
||||
: WebCachedImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<WebCachedSource>(
|
||||
std::make_unique<Image>(std::make_unique<WebCachedSource>(
|
||||
location,
|
||||
box,
|
||||
size)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
size))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(
|
||||
|
@ -302,29 +306,32 @@ ImagePtr Create(
|
|||
int width,
|
||||
int height,
|
||||
int size) {
|
||||
const auto key = storageKey(location);
|
||||
auto i = WebCachedImages.constFind(key);
|
||||
if (i == WebCachedImages.cend()) {
|
||||
i = WebCachedImages.insert(
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = WebCachedImages.find(key);
|
||||
const auto image = (i != end(WebCachedImages))
|
||||
? i->second.get()
|
||||
: WebCachedImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<WebCachedSource>(
|
||||
std::make_unique<Image>(std::make_unique<WebCachedSource>(
|
||||
location,
|
||||
width,
|
||||
height,
|
||||
size)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
size))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
ImagePtr Create(const GeoPointLocation &location) {
|
||||
const auto key = storageKey(location);
|
||||
auto i = GeoPointImages.constFind(key);
|
||||
if (i == GeoPointImages.cend()) {
|
||||
i = GeoPointImages.insert(
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = GeoPointImages.find(key);
|
||||
const auto image = (i != end(GeoPointImages))
|
||||
? i->second.get()
|
||||
: GeoPointImages.emplace(
|
||||
key,
|
||||
new Image(std::make_unique<GeoPointSource>(location)));
|
||||
}
|
||||
return ImagePtr(i.value());
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<GeoPointSource>(location))
|
||||
).first->second.get();
|
||||
return ImagePtr(image);
|
||||
}
|
||||
|
||||
} // namespace Images
|
||||
|
|
|
@ -27,36 +27,115 @@ ImagePtr::operator bool() const {
|
|||
return !_data->isNull();
|
||||
}
|
||||
|
||||
StorageImageLocation StorageImageLocation::Null;
|
||||
WebFileLocation WebFileLocation::Null;
|
||||
|
||||
StorageImageLocation::StorageImageLocation(
|
||||
int32 width,
|
||||
int32 height,
|
||||
int32 dc,
|
||||
const uint64 &volume,
|
||||
int32 local,
|
||||
const uint64 &secret,
|
||||
const QByteArray &fileReference)
|
||||
: _widthheight(packIntInt(width, height))
|
||||
, _dclocal(packIntInt(dc, local))
|
||||
, _volume(volume)
|
||||
, _secret(secret)
|
||||
, _fileReference(fileReference) {
|
||||
bool StorageFileLocation::valid() const {
|
||||
switch (_type) {
|
||||
case Type::General:
|
||||
return (_dcId != 0) && (_volumeId != 0) && (_localId != 0);
|
||||
|
||||
case Type::Encrypted:
|
||||
case Type::Secure:
|
||||
case Type::Document:
|
||||
return (_dcId != 0) && (_id != 0);
|
||||
|
||||
case Type::Photo:
|
||||
return (_dcId != 0) && (_id != 0) && (_sizeLetter != 0);
|
||||
|
||||
case Type::Takeout:
|
||||
return true;
|
||||
|
||||
case Type::PeerPhoto:
|
||||
case Type::StickerSetThumb:
|
||||
return (_dcId != 0) && (_id != 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
InMemoryKey StorageFileLocation::inMemoryKey() const {
|
||||
switch (_type) {
|
||||
case Type::General:
|
||||
case Type::PeerPhoto:
|
||||
case Type::StickerSetThumb:
|
||||
return InMemoryKey(
|
||||
(uint64(_type) << 56) | (uint64(_dcId) << 40) | uint32(_localId),
|
||||
_volumeId);
|
||||
|
||||
case Type::Encrypted:
|
||||
case Type::Secure:
|
||||
return InMemoryKey(
|
||||
(uint64(_type) << 56) | (uint64(_dcId) << 40),
|
||||
_id);
|
||||
|
||||
case Type::Document:
|
||||
case Type::Photo:
|
||||
return InMemoryKey(
|
||||
(uint64(_type) << 56) | (uint64(_dcId) << 40) | _sizeLetter,
|
||||
_id);
|
||||
|
||||
case Type::Takeout:
|
||||
return InMemoryKey(
|
||||
(uint64(_type) << 56),
|
||||
0);
|
||||
}
|
||||
return InMemoryKey();
|
||||
}
|
||||
|
||||
bool operator==(const StorageFileLocation &a, const StorageFileLocation &b) {
|
||||
const auto valid = a.valid();
|
||||
if (valid != b.valid()) {
|
||||
return false;
|
||||
} else if (!valid) {
|
||||
return true;
|
||||
}
|
||||
const auto type = a._type;
|
||||
if (type != b._type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
using Type = StorageFileLocation::Type;
|
||||
switch (type) {
|
||||
case Type::General:
|
||||
return (a._dcId == b._dcId)
|
||||
&& (a._volumeId == b._volumeId)
|
||||
&& (a._localId == b._localId);
|
||||
|
||||
case Type::Encrypted:
|
||||
case Type::Secure:
|
||||
return (a._dcId == b._dcId) && (a._id == b._id);
|
||||
|
||||
case Type::Photo:
|
||||
case Type::Document:
|
||||
return (a._dcId == b._dcId)
|
||||
&& (a._id == b._id)
|
||||
&& (a._sizeLetter == b._sizeLetter);
|
||||
|
||||
case Type::Takeout:
|
||||
return true;
|
||||
|
||||
case Type::PeerPhoto:
|
||||
return (a._dcId == b._dcId)
|
||||
&& (a._volumeId == b._volumeId)
|
||||
&& (a._localId == b._localId)
|
||||
&& (a._id == b._id)
|
||||
&& (a._sizeLetter == b._sizeLetter);
|
||||
|
||||
case Type::StickerSetThumb:
|
||||
return (a._dcId == b._dcId)
|
||||
&& (a._volumeId == b._volumeId)
|
||||
&& (a._localId == b._localId)
|
||||
&& (a._id == b._id);
|
||||
};
|
||||
Unexpected("Type in StorageFileLocation::operator==.");
|
||||
}
|
||||
|
||||
StorageImageLocation::StorageImageLocation(
|
||||
int32 width,
|
||||
int32 height,
|
||||
const MTPDfileLocation &location)
|
||||
: StorageImageLocation(
|
||||
width,
|
||||
height,
|
||||
location.vdc_id.v,
|
||||
location.vvolume_id.v,
|
||||
location.vlocal_id.v,
|
||||
location.vsecret.v,
|
||||
location.vfile_reference.v) {
|
||||
const StorageFileLocation &file,
|
||||
int width,
|
||||
int height)
|
||||
: _file(file)
|
||||
, _width(width)
|
||||
, _height(height) {
|
||||
}
|
||||
|
||||
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark)
|
||||
|
|
|
@ -19,128 +19,122 @@ enum LoadToCacheSetting {
|
|||
LoadToCacheAsWell,
|
||||
};
|
||||
|
||||
inline uint32 packInt(int32 a) {
|
||||
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
|
||||
}
|
||||
inline int32 unpackInt(uint32 a) {
|
||||
return (a > 0x7FFFFFFFU) ? int32(int64(a) - 0x100000000LL) : int32(a);
|
||||
}
|
||||
inline uint64 packUIntUInt(uint32 a, uint32 b) {
|
||||
return (uint64(a) << 32) | uint64(b);
|
||||
}
|
||||
inline uint64 packUIntInt(uint32 a, int32 b) {
|
||||
return packUIntUInt(a, packInt(b));
|
||||
}
|
||||
inline uint64 packIntUInt(int32 a, uint32 b) {
|
||||
return packUIntUInt(packInt(a), b);
|
||||
}
|
||||
inline uint64 packIntInt(int32 a, int32 b) {
|
||||
return packUIntUInt(packInt(a), packInt(b));
|
||||
}
|
||||
inline uint32 unpackUIntFirst(uint64 v) {
|
||||
return uint32(v >> 32);
|
||||
}
|
||||
inline int32 unpackIntFirst(uint64 v) {
|
||||
return unpackInt(unpackUIntFirst(v));
|
||||
}
|
||||
inline uint32 unpackUIntSecond(uint64 v) {
|
||||
return uint32(v & 0xFFFFFFFFULL);
|
||||
}
|
||||
inline int32 unpackIntSecond(uint64 v) {
|
||||
return unpackInt(unpackUIntSecond(v));
|
||||
using InMemoryKey = std::pair<uint64, uint64>;
|
||||
|
||||
class StorageFileLocation {
|
||||
public:
|
||||
// Those are used in serialization, don't change.
|
||||
enum class Type : uchar {
|
||||
General = 0x00,
|
||||
Encrypted = 0x01,
|
||||
Document = 0x02,
|
||||
Secure = 0x03,
|
||||
Takeout = 0x04,
|
||||
Photo = 0x05,
|
||||
PeerPhoto = 0x06,
|
||||
StickerSetThumb = 0x07,
|
||||
};
|
||||
|
||||
StorageFileLocation() = default;
|
||||
StorageFileLocation(MTP::DcId dcId, const MTPInputFileLocation &tl);
|
||||
|
||||
[[nodiscard]] MTP::DcId dcId() const;
|
||||
[[nodiscard]] MTPInputFileLocation tl() const;
|
||||
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
[[nodiscard]] static std::optional<StorageFileLocation> FromSerialized(
|
||||
const QByteArray &serialized);
|
||||
|
||||
[[nodiscard]] bool valid() const;
|
||||
[[nodiscard]] InMemoryKey inMemoryKey() const;
|
||||
|
||||
[[nodiscard]] QByteArray fileReference() const;
|
||||
bool refreshFileReference(const QByteArray &data) {
|
||||
if (data.isEmpty() || _fileReference == data) {
|
||||
return false;
|
||||
}
|
||||
_fileReference = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
friend bool operator==(
|
||||
const StorageFileLocation &a,
|
||||
const StorageFileLocation &b);
|
||||
|
||||
uint16 _dcId = 0;
|
||||
Type _type = Type::General;
|
||||
uint8 _sizeLetter = 0;
|
||||
int32 _localId = 0;
|
||||
uint64 _id = 0;
|
||||
uint64 _accessHash = 0;
|
||||
uint64 _volumeId = 0;
|
||||
QByteArray _fileReference;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator!=(
|
||||
const StorageFileLocation &a,
|
||||
const StorageFileLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
class StorageImageLocation {
|
||||
public:
|
||||
StorageImageLocation() = default;
|
||||
StorageImageLocation(
|
||||
int32 width,
|
||||
int32 height,
|
||||
int32 dc,
|
||||
const uint64 &volume,
|
||||
int32 local,
|
||||
const uint64 &secret,
|
||||
const QByteArray &fileReference);
|
||||
StorageImageLocation(
|
||||
int32 width,
|
||||
int32 height,
|
||||
const MTPDfileLocation &location);
|
||||
const StorageFileLocation &file,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
bool isNull() const {
|
||||
return !_dclocal;
|
||||
[[nodiscard]] QByteArray serialize() const;
|
||||
[[nodiscard]] static std::optional<StorageImageLocation> FromSerialized(
|
||||
const QByteArray &serialized);
|
||||
|
||||
[[nodiscard]] const StorageFileLocation &file() const {
|
||||
return _file;
|
||||
}
|
||||
int32 width() const {
|
||||
return unpackIntFirst(_widthheight);
|
||||
[[nodiscard]] int width() const {
|
||||
return _width;
|
||||
}
|
||||
int32 height() const {
|
||||
return unpackIntSecond(_widthheight);
|
||||
}
|
||||
void setSize(int32 width, int32 height) {
|
||||
_widthheight = packIntInt(width, height);
|
||||
}
|
||||
int32 dc() const {
|
||||
return unpackIntFirst(_dclocal);
|
||||
}
|
||||
uint64 volume() const {
|
||||
return _volume;
|
||||
}
|
||||
int32 local() const {
|
||||
return unpackIntSecond(_dclocal);
|
||||
}
|
||||
uint64 secret() const {
|
||||
return _secret;
|
||||
}
|
||||
QByteArray fileReference() const {
|
||||
return _fileReference;
|
||||
}
|
||||
void refreshFileReference(const QByteArray &data) {
|
||||
if (!data.isEmpty()) {
|
||||
_fileReference = data;
|
||||
}
|
||||
[[nodiscard]] int height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
static StorageImageLocation FromMTP(
|
||||
int32 width,
|
||||
int32 height,
|
||||
const MTPFileLocation &location) {
|
||||
if (location.type() == mtpc_fileLocation) {
|
||||
const auto &data = location.c_fileLocation();
|
||||
return StorageImageLocation(width, height, data);
|
||||
}
|
||||
return StorageImageLocation(width, height, 0, 0, 0, 0, {});
|
||||
}
|
||||
static StorageImageLocation FromMTP(const MTPPhotoSize &size) {
|
||||
switch (size.type()) {
|
||||
case mtpc_photoSize: {
|
||||
const auto &data = size.c_photoSize();
|
||||
return FromMTP(data.vw.v, data.vh.v, data.vlocation);
|
||||
} break;
|
||||
case mtpc_photoCachedSize: {
|
||||
const auto &data = size.c_photoCachedSize();
|
||||
return FromMTP(data.vw.v, data.vh.v, data.vlocation);
|
||||
} break;
|
||||
}
|
||||
return StorageImageLocation();
|
||||
void setSize(int width, int height) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
static StorageImageLocation Null;
|
||||
[[nodiscard]] bool valid() const {
|
||||
return _file.valid();
|
||||
}
|
||||
[[nodiscard]] InMemoryKey inMemoryKey() const {
|
||||
return _file.inMemoryKey();
|
||||
}
|
||||
[[nodiscard]] QByteArray fileReference() const {
|
||||
return _file.fileReference();
|
||||
}
|
||||
bool refreshFileReference(const QByteArray &data) {
|
||||
return _file.refreshFileReference(data);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 _widthheight = 0;
|
||||
uint64 _dclocal = 0;
|
||||
uint64 _volume = 0;
|
||||
uint64 _secret = 0;
|
||||
QByteArray _fileReference;
|
||||
|
||||
friend inline bool operator==(
|
||||
const StorageImageLocation &a,
|
||||
const StorageImageLocation &b) {
|
||||
return (a._dclocal == b._dclocal) && (a._volume == b._volume);
|
||||
return (a._file == b._file);
|
||||
}
|
||||
|
||||
StorageFileLocation _file;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
inline bool operator!=(
|
||||
const StorageImageLocation &a,
|
||||
const StorageImageLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
|
@ -230,29 +224,27 @@ private:
|
|||
|
||||
};
|
||||
|
||||
typedef QPair<uint64, uint64> StorageKey;
|
||||
inline uint64 storageMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
inline InMemoryKey inMemoryKey(const StorageFileLocation &location) {
|
||||
return location.inMemoryKey();
|
||||
}
|
||||
inline StorageKey storageKey(int32 dc, const uint64 &volume, int32 local) {
|
||||
return StorageKey(storageMix32To64(dc, local), volume);
|
||||
|
||||
inline InMemoryKey inMemoryKey(const StorageImageLocation &location) {
|
||||
return location.inMemoryKey();
|
||||
}
|
||||
inline StorageKey storageKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
|
||||
inline InMemoryKey inMemoryKey(const WebFileLocation &location) {
|
||||
auto result = InMemoryKey();
|
||||
const auto &url = location.url();
|
||||
const auto sha = hashSha1(url.data(), url.size());
|
||||
bytes::copy(
|
||||
bytes::object_as_span(&result),
|
||||
bytes::make_span(sha).subspan(0, sizeof(result)));
|
||||
result.first |= (uint64(uint16(location.dc())) << 56);
|
||||
return result;
|
||||
}
|
||||
inline StorageKey storageKey(const StorageImageLocation &location) {
|
||||
return storageKey(location.dc(), location.volume(), location.local());
|
||||
}
|
||||
inline StorageKey storageKey(const WebFileLocation &location) {
|
||||
auto url = location.url();
|
||||
auto sha = hashSha1(url.data(), url.size());
|
||||
return storageKey(
|
||||
location.dc(),
|
||||
*reinterpret_cast<const uint64*>(sha.data()),
|
||||
*reinterpret_cast<const int32*>(sha.data() + sizeof(uint64)));
|
||||
}
|
||||
inline StorageKey storageKey(const GeoPointLocation &location) {
|
||||
return StorageKey(
|
||||
|
||||
inline InMemoryKey inMemoryKey(const GeoPointLocation &location) {
|
||||
return InMemoryKey(
|
||||
(uint64(std::round(std::abs(location.lat + 360.) * 1000000)) << 32)
|
||||
| uint64(std::round(std::abs(location.lon + 360.) * 1000000)),
|
||||
(uint64(location.width) << 32) | uint64(location.height));
|
||||
|
|
|
@ -885,7 +885,7 @@ void UserpicButton::prepareUserpicPixmap() {
|
|||
});
|
||||
_userpicUniqueKey = _userpicHasImage
|
||||
? _peer->userpicUniqueKey()
|
||||
: StorageKey();
|
||||
: InMemoryKey();
|
||||
}
|
||||
|
||||
FeedUserpicButton::FeedUserpicButton(
|
||||
|
|
|
@ -213,7 +213,7 @@ private:
|
|||
QPixmap _userpic, _oldUserpic;
|
||||
bool _userpicHasImage = false;
|
||||
bool _userpicCustom = false;
|
||||
StorageKey _userpicUniqueKey;
|
||||
InMemoryKey _userpicUniqueKey;
|
||||
Animation _a_appearance;
|
||||
QImage _result;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ CachedUserpics::CachedUserpics(Type type)
|
|||
QDir().mkpath(cWorkingDir() + qsl("tdata/temp"));
|
||||
}
|
||||
|
||||
QString CachedUserpics::get(const StorageKey &key, PeerData *peer) {
|
||||
QString CachedUserpics::get(const InMemoryKey &key, PeerData *peer) {
|
||||
auto ms = crl::now();
|
||||
auto i = _images.find(key);
|
||||
if (i != _images.cend()) {
|
||||
|
@ -102,7 +102,7 @@ void CachedUserpics::onClear() {
|
|||
CachedUserpics::~CachedUserpics() {
|
||||
if (_someSavedFlag) {
|
||||
crl::time result = 0;
|
||||
for_const (auto &item, _images) {
|
||||
for (const auto &item : std::as_const(_images)) {
|
||||
QFile(item.path).remove();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
};
|
||||
CachedUserpics(Type type);
|
||||
|
||||
QString get(const StorageKey &key, PeerData *peer);
|
||||
QString get(const InMemoryKey &key, PeerData *peer);
|
||||
|
||||
~CachedUserpics();
|
||||
|
||||
|
@ -39,7 +39,7 @@ private:
|
|||
crl::time until;
|
||||
QString path;
|
||||
};
|
||||
using Images = QMap<StorageKey, Image>;
|
||||
using Images = QMap<InMemoryKey, Image>;
|
||||
Images _images;
|
||||
bool _someSavedFlag = false;
|
||||
base::Timer _clearTimer;
|
||||
|
|
Loading…
Reference in New Issue