diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 8ca27e144..3092ae4ee 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -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; diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 4d7722e09..0e3e6c66e 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -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 { diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 20864dc15..4dd2751df 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -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; diff --git a/Telegram/SourceFiles/export/export_api_wrap.cpp b/Telegram/SourceFiles/export/export_api_wrap.cpp index 8583e34a9..e937538fe 100644 --- a/Telegram/SourceFiles/export/export_api_wrap.cpp +++ b/Telegram/SourceFiles/export/export_api_wrap.cpp @@ -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; } diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index 6ed7f15e8..48ed97f01 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -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); diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index 75952454e..c1226b021 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -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; diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index ad99a964c..850d9a852 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -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); diff --git a/Telegram/SourceFiles/ui/empty_userpic.cpp b/Telegram/SourceFiles/ui/empty_userpic.cpp index 4a00805ab..fdef72b68 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.cpp +++ b/Telegram/SourceFiles/ui/empty_userpic.cpp @@ -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) { diff --git a/Telegram/SourceFiles/ui/empty_userpic.h b/Telegram/SourceFiles/ui/empty_userpic.h index e78a0f881..4c8033750 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.h +++ b/Telegram/SourceFiles/ui/empty_userpic.h @@ -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, diff --git a/Telegram/SourceFiles/ui/image/image.cpp b/Telegram/SourceFiles/ui/image/image.cpp index 4694106e0..02c62d30f 100644 --- a/Telegram/SourceFiles/ui/image/image.cpp +++ b/Telegram/SourceFiles/ui/image/image.cpp @@ -22,11 +22,11 @@ namespace { // After 128 MB of unpacked images we try to clear some memory. constexpr auto kMemoryForCache = 128 * 1024 * 1024; -QMap LocalFileImages; -QMap WebUrlImages; -QMap StorageImages; -QMap WebCachedImages; -QMap GeoPointImages; +std::map> LocalFileImages; +std::map> WebUrlImages; +std::unordered_map> StorageImages; +std::unordered_map> WebCachedImages; +std::unordered_map> 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(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( + std::make_unique(std::make_unique(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( + std::make_unique( 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(url, box))); - } - return ImagePtr(i.value()); + std::make_unique(std::make_unique(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(url, width, height))); - } else { - i.value()->setInformation(0, width, height); + std::make_unique( + std::make_unique(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(location, size))); - } else { - i.value()->refreshFileReference(location.fileReference()); + std::make_unique( + std::make_unique(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( - location, - bytes.size()))); - } else { - i.value()->refreshFileReference(location.fileReference()); + std::make_unique( + std::make_unique(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 &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( + std::make_unique(std::make_unique( 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( + std::make_unique(std::make_unique( 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(location))); - } - return ImagePtr(i.value()); + std::make_unique( + std::make_unique(location)) + ).first->second.get(); + return ImagePtr(image); } } // namespace Images diff --git a/Telegram/SourceFiles/ui/image/image_location.cpp b/Telegram/SourceFiles/ui/image/image_location.cpp index d50f47ff9..5e2e830f9 100644 --- a/Telegram/SourceFiles/ui/image/image_location.cpp +++ b/Telegram/SourceFiles/ui/image/image_location.cpp @@ -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) diff --git a/Telegram/SourceFiles/ui/image/image_location.h b/Telegram/SourceFiles/ui/image/image_location.h index 37bc1f363..246f4dd81 100644 --- a/Telegram/SourceFiles/ui/image/image_location.h +++ b/Telegram/SourceFiles/ui/image/image_location.h @@ -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; + +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 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 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 StorageKey; -inline uint64 storageMix32To64(int32 a, int32 b) { - return (uint64(*reinterpret_cast(&a)) << 32) | uint64(*reinterpret_cast(&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(sha.data()), - *reinterpret_cast(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)); diff --git a/Telegram/SourceFiles/ui/special_buttons.cpp b/Telegram/SourceFiles/ui/special_buttons.cpp index 38d4f0562..c79e47c57 100644 --- a/Telegram/SourceFiles/ui/special_buttons.cpp +++ b/Telegram/SourceFiles/ui/special_buttons.cpp @@ -885,7 +885,7 @@ void UserpicButton::prepareUserpicPixmap() { }); _userpicUniqueKey = _userpicHasImage ? _peer->userpicUniqueKey() - : StorageKey(); + : InMemoryKey(); } FeedUserpicButton::FeedUserpicButton( diff --git a/Telegram/SourceFiles/ui/special_buttons.h b/Telegram/SourceFiles/ui/special_buttons.h index 69b057c1e..8df167f4e 100644 --- a/Telegram/SourceFiles/ui/special_buttons.h +++ b/Telegram/SourceFiles/ui/special_buttons.h @@ -213,7 +213,7 @@ private: QPixmap _userpic, _oldUserpic; bool _userpicHasImage = false; bool _userpicCustom = false; - StorageKey _userpicUniqueKey; + InMemoryKey _userpicUniqueKey; Animation _a_appearance; QImage _result; diff --git a/Telegram/SourceFiles/window/notifications_utilities.cpp b/Telegram/SourceFiles/window/notifications_utilities.cpp index 9b3714431..6bfd7a745 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.cpp +++ b/Telegram/SourceFiles/window/notifications_utilities.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/window/notifications_utilities.h b/Telegram/SourceFiles/window/notifications_utilities.h index 1e0b9bde9..f8402e46d 100644 --- a/Telegram/SourceFiles/window/notifications_utilities.h +++ b/Telegram/SourceFiles/window/notifications_utilities.h @@ -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; + using Images = QMap; Images _images; bool _someSavedFlag = false; base::Timer _clearTimer;