| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "ui/image/image_location.h"
- #include "ui/image/image.h"
- #include "platform/platform_specific.h"
- #include "storage/cache/storage_cache_types.h"
- #include "storage/serialize_common.h"
- #include "data/data_file_origin.h"
- #include "base/overload.h"
- #include "main/main_session.h"
- #include <QtCore/QBuffer>
- namespace {
- constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL;
- constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL;
- constexpr auto kPhotoBaseCacheTag = 0x0000000000020000ULL;
- constexpr auto kPhotoBaseCacheMask = 0x000000000000FF00ULL;
- constexpr auto kNonStorageLocationToken = quint8(0x10);
- constexpr auto kLegacyInMessagePeerIdFlag = quint8(0x08);
- constexpr auto kModernLocationFlag = quint8(0x20);
- constexpr auto kInMessageFieldsFlag = quint8(0x40);
- enum class NonStorageLocationType : quint8 {
- Web,
- Geo,
- Url,
- Memory,
- AudioAlbumThumb,
- };
- MTPInputPeer GenerateInputPeer(
- PeerId id,
- uint64 accessHash,
- PeerId inMessagePeerId,
- int32 inMessageId,
- UserId self) {
- const auto bareId = [&] {
- return peerToBareMTPInt(id);
- };
- if (inMessageId && peerIsUser(inMessagePeerId)) {
- return MTP_inputPeerUserFromMessage(
- GenerateInputPeer(id, accessHash, 0, 0, self),
- MTP_int(inMessageId),
- MTP_long(peerToUser(inMessagePeerId).bare));
- } else if (inMessageId && peerIsChannel(inMessagePeerId)) {
- return MTP_inputPeerChannelFromMessage(
- GenerateInputPeer(id, accessHash, 0, 0, self),
- MTP_int(inMessageId),
- MTP_long(peerToChannel(inMessagePeerId).bare));
- } else if (!id) {
- return MTP_inputPeerEmpty();
- } else if (id == peerFromUser(self)) {
- return MTP_inputPeerSelf();
- } else if (peerIsUser(id)) {
- return MTP_inputPeerUser(bareId(), MTP_long(accessHash));
- } else if (peerIsChat(id)) {
- return MTP_inputPeerChat(bareId());
- } else if (peerIsChannel(id)) {
- return MTP_inputPeerChannel(bareId(), MTP_long(accessHash));
- } else {
- return MTP_inputPeerEmpty();
- }
- }
- } // namespace
- WebFileLocation WebFileLocation::Null;
- StorageFileLocation::StorageFileLocation(
- int32 dcId,
- UserId self,
- const MTPInputFileLocation &tl)
- : _dcId(dcId) {
- tl.match([&](const MTPDinputFileLocation &data) {
- _type = Type::Legacy;
- _volumeId = data.vvolume_id().v;
- _localId = data.vlocal_id().v;
- _accessHash = data.vsecret().v;
- _fileReference = data.vfile_reference().v;
- }, [&](const MTPDinputEncryptedFileLocation &data) {
- _type = Type::Encrypted;
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- }, [&](const MTPDinputDocumentFileLocation &data) {
- _type = Type::Document;
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- _fileReference = data.vfile_reference().v;
- _sizeLetter = data.vthumb_size().v.isEmpty()
- ? uint8(0)
- : uint8(data.vthumb_size().v[0]);
- }, [&](const MTPDinputSecureFileLocation &data) {
- _type = Type::Secure;
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- }, [&](const MTPDinputTakeoutFileLocation &data) {
- _type = Type::Takeout;
- }, [&](const MTPDinputPhotoFileLocation &data) {
- _type = Type::Photo;
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- _fileReference = data.vfile_reference().v;
- _sizeLetter = data.vthumb_size().v.isEmpty()
- ? char(0)
- : data.vthumb_size().v[0];
- }, [&](const MTPDinputPhotoLegacyFileLocation &data) {
- _type = Type::Legacy;
- _volumeId = data.vvolume_id().v;
- _localId = data.vlocal_id().v;
- _accessHash = data.vsecret().v;
- _fileReference = data.vfile_reference().v;
- }, [&](const MTPDinputPeerPhotoFileLocation &data) {
- _type = Type::PeerPhoto;
- const auto fillPeer = base::overload([&](
- const MTPDinputPeerEmpty &data) {
- _id = 0;
- }, [&](const MTPDinputPeerSelf &data) {
- _id = peerFromUser(self).value;
- }, [&](const MTPDinputPeerChat &data) {
- _id = peerFromChat(data.vchat_id()).value;
- }, [&](const MTPDinputPeerUser &data) {
- _id = peerFromUser(data.vuser_id()).value;
- _accessHash = data.vaccess_hash().v;
- }, [&](const MTPDinputPeerChannel &data) {
- _id = peerFromChannel(data.vchannel_id()).value;
- _accessHash = data.vaccess_hash().v;
- });
- data.vpeer().match(fillPeer, [&](
- const MTPDinputPeerUserFromMessage &data) {
- data.vpeer().match(fillPeer, [&](auto &&) {
- // Bad data provided.
- _id = _accessHash = 0;
- });
- _inMessagePeerId = peerFromUser(data.vuser_id());
- _inMessageId = data.vmsg_id().v;
- }, [&](const MTPDinputPeerChannelFromMessage &data) {
- data.vpeer().match(fillPeer, [&](auto &&) {
- // Bad data provided.
- _id = _accessHash = 0;
- });
- _inMessagePeerId = peerFromChannel(data.vchannel_id());
- _inMessageId = data.vmsg_id().v;
- });
- _volumeId = data.vphoto_id().v;
- _sizeLetter = data.is_big() ? 'c' : 'a';
- // _localId place is used in serialization.
- Ensures(_localId == 0);
- }, [&](const MTPDinputStickerSetThumb &data) {
- _type = Type::StickerSetThumb;
- data.vstickerset().match([&](const MTPDinputStickerSetEmpty &data) {
- _id = 0;
- }, [&](const MTPDinputStickerSetID &data) {
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- }, [&](const auto &data) {
- Unexpected("InputStickerSet type in StorageFileLocation.");
- });
- _volumeId = 0;
- _localId = data.vthumb_version().v;
- }, [&](const MTPDinputGroupCallStream &data) {
- _type = Type::GroupCallStream;
- data.vcall().match([&](const MTPDinputGroupCall &data) {
- _id = data.vid().v;
- _accessHash = data.vaccess_hash().v;
- });
- _volumeId = data.vtime_ms().v;
- _localId = data.vscale().v;
- _sizeLetter = uint8(data.vvideo_channel().value_or_empty() & 0x3F)
- | uint8((data.vvideo_quality().value_or_empty() & 0x03) << 6);
- });
- }
- StorageFileLocation StorageFileLocation::convertToModernPeerPhoto(
- uint64 id,
- uint64 accessHash,
- uint64 photoId) const {
- if (_type != Type::Legacy && _type != Type::PeerPhoto) {
- return *this;
- } else if (!photoId) {
- return StorageFileLocation();
- }
- auto result = *this;
- result._type = Type::PeerPhoto;
- result._id = id;
- result._accessHash = accessHash;
- result._sizeLetter = uint8('a');
- result._volumeId = photoId;
- result._localId = 0;
- result._inMessagePeerId = 0;
- result._inMessageId = 0;
- return result;
- }
- int32 StorageFileLocation::dcId() const {
- return _dcId;
- }
- uint64 StorageFileLocation::objectId() const {
- return _id;
- }
- MTPInputFileLocation StorageFileLocation::tl(UserId self) const {
- switch (_type) {
- case Type::Legacy:
- return MTP_inputFileLocation(
- MTP_long(_volumeId),
- MTP_int(_localId),
- MTP_long(_accessHash),
- MTP_bytes(_fileReference));
- case Type::Encrypted:
- return MTP_inputSecureFileLocation(
- MTP_long(_id),
- MTP_long(_accessHash));
- case Type::Document:
- return MTP_inputDocumentFileLocation(
- MTP_long(_id),
- MTP_long(_accessHash),
- MTP_bytes(_fileReference),
- MTP_string(_sizeLetter
- ? std::string(1, char(_sizeLetter))
- : std::string()));
- case Type::Secure:
- return MTP_inputSecureFileLocation(
- MTP_long(_id),
- MTP_long(_accessHash));
- case Type::Takeout:
- return MTP_inputTakeoutFileLocation();
- case Type::Photo:
- return MTP_inputPhotoFileLocation(
- MTP_long(_id),
- MTP_long(_accessHash),
- MTP_bytes(_fileReference),
- MTP_string(std::string(1, char(_sizeLetter))));
- case Type::PeerPhoto:
- return MTP_inputPeerPhotoFileLocation(
- MTP_flags((_sizeLetter == 'c')
- ? MTPDinputPeerPhotoFileLocation::Flag::f_big
- : MTPDinputPeerPhotoFileLocation::Flag(0)),
- GenerateInputPeer(
- PeerId(_id),
- _accessHash,
- _inMessagePeerId,
- _inMessageId,
- self),
- MTP_long(_volumeId));
- case Type::StickerSetThumb:
- return MTP_inputStickerSetThumb(
- MTP_inputStickerSetID(MTP_long(_id), MTP_long(_accessHash)),
- MTP_int(_localId));
- case Type::GroupCallStream:
- return MTP_inputGroupCallStream(
- MTP_flags((_sizeLetter != 0)
- ? (MTPDinputGroupCallStream::Flag::f_video_channel
- | MTPDinputGroupCallStream::Flag::f_video_quality)
- : MTPDinputGroupCallStream::Flag(0)),
- MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash)),
- MTP_long(_volumeId),
- MTP_int(_localId),
- MTP_int(_sizeLetter & 0x3F),
- MTP_int((_sizeLetter >> 6) & 0x03));
- }
- Unexpected("Type in StorageFileLocation::tl.");
- }
- QByteArray StorageFileLocation::serialize() const {
- auto result = QByteArray();
- if (valid()) {
- result.reserve(serializeSize());
- auto buffer = QBuffer(&result);
- buffer.open(QIODevice::WriteOnly);
- auto stream = QDataStream(&buffer);
- stream.setVersion(QDataStream::Qt_5_1);
- Assert(!(quint8(_type) & kModernLocationFlag)
- && !(quint8(_type) & kInMessageFieldsFlag));
- auto typeWithFlags = quint8(_type);
- typeWithFlags |= kModernLocationFlag;
- auto field1 = qint32(_localId);
- auto field2 = qint32(0);
- if (_inMessagePeerId != 0) {
- Assert(field1 == 0);
- typeWithFlags |= kInMessageFieldsFlag;
- field1 = qint32(uint32(_inMessagePeerId.value >> 32));
- field2 = qint32(uint32(_inMessagePeerId.value & 0xFFFFFFFFULL));
- }
- Assert(typeWithFlags != kNonStorageLocationToken);
- stream
- << quint16(_dcId)
- << typeWithFlags
- << quint8(_sizeLetter)
- << field1
- << quint64(_id)
- << quint64(_accessHash)
- << quint64(_volumeId)
- << field2
- << qint32(_inMessageId)
- << _fileReference;
- }
- return result;
- }
- int StorageFileLocation::serializeSize() const {
- return valid()
- ? int(sizeof(uint64) * 5 + Serialize::bytearraySize(_fileReference))
- : 0;
- }
- std::optional<StorageFileLocation> StorageFileLocation::FromSerialized(
- const QByteArray &serialized) {
- if (serialized.isEmpty()) {
- return StorageFileLocation();
- }
- quint16 dcId = 0;
- quint8 typeWithFlags = 0;
- quint8 sizeLetter = 0;
- qint32 field1 = 0;
- quint64 id = 0;
- quint64 accessHash = 0;
- quint64 volumeId = 0;
- qint32 field2 = 0;
- qint32 inMessageId = 0;
- QByteArray fileReference;
- auto stream = QDataStream(serialized);
- stream.setVersion(QDataStream::Qt_5_1);
- stream
- >> dcId
- >> typeWithFlags;
- if (typeWithFlags == kNonStorageLocationToken) {
- return std::nullopt;
- }
- stream
- >> sizeLetter
- >> field1
- >> id
- >> accessHash
- >> volumeId;
- const auto modern = ((typeWithFlags & kModernLocationFlag) != 0);
- const auto inMessageFields
- = ((typeWithFlags & kInMessageFieldsFlag) != 0);
- if (modern) {
- stream >> field2 >> inMessageId;
- typeWithFlags &= ~kModernLocationFlag;
- if (inMessageFields) {
- typeWithFlags &= ~kInMessageFieldsFlag;
- }
- } else if (typeWithFlags & kLegacyInMessagePeerIdFlag) {
- typeWithFlags &= ~kLegacyInMessagePeerIdFlag;
- stream >> field2 >> inMessageId;
- }
- stream >> fileReference;
- auto result = StorageFileLocation();
- result._dcId = dcId;
- result._type = Type(typeWithFlags);
- result._sizeLetter = sizeLetter;
- result._accessHash = accessHash;
- result._volumeId = volumeId;
- result._inMessageId = inMessageId;
- result._fileReference = fileReference;
- if (modern) {
- result._id = id;
- if (inMessageFields) {
- result._localId = 0;
- result._inMessagePeerId = PeerId(
- (uint64(uint32(field1)) << 32) | uint64(uint32(field2)));
- } else {
- result._localId = field1;
- result._inMessagePeerId = 0;
- }
- } else {
- result._id = (result._type == Type::PeerPhoto)
- ? DeserializePeerId(id).value
- : id;
- result._localId = (result._type == Type::PeerPhoto)
- ? 0
- : field1;
- result._inMessagePeerId = (field2 && result._type == Type::PeerPhoto)
- ? ((field2 > 0)
- ? peerFromUser(UserId(field2))
- : peerFromChannel(ChannelId(-field2)))
- : PeerId();
- }
- if (result._type == Type::StickerSetThumb && result._volumeId != 0) {
- // Legacy field values that cannot be converted to modern.
- // No information about thumb_version, which is required.
- return std::nullopt;
- }
- return (stream.status() == QDataStream::Ok && result.valid())
- ? std::make_optional(result)
- : std::nullopt;
- }
- StorageFileLocation::Type StorageFileLocation::type() const {
- return _type;
- }
- bool StorageFileLocation::valid() const {
- switch (_type) {
- case Type::Legacy:
- 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);
- case Type::GroupCallStream:
- return (_dcId != 0) && (_id != 0) && (_volumeId != 0);
- }
- return false;
- }
- bool StorageFileLocation::isLegacy() const {
- return (_type == Type::Legacy);
- }
- bool StorageFileLocation::isDocumentThumbnail() const {
- return (_type == Type::Document) && (_sizeLetter != 0);
- }
- Storage::Cache::Key StorageFileLocation::cacheKey() const {
- using Key = Storage::Cache::Key;
- // Skip '1' for legacy document cache keys.
- // Skip '2' because it is used for good (fullsize) document thumbnails.
- const auto shifted = ((uint64(_type) + 3) << 8);
- const auto sliced = uint64(_dcId) & 0xFFULL;
- switch (_type) {
- case Type::Legacy:
- case Type::PeerPhoto:
- case Type::StickerSetThumb:
- return Key{
- shifted | sliced | (uint64(uint32(_localId)) << 16),
- _volumeId };
- case Type::Encrypted:
- case Type::Secure:
- return Key{ shifted | sliced, _id };
- case Type::Document:
- // Keep old cache keys for documents.
- if (_sizeLetter == 0) {
- return Data::DocumentCacheKey(_dcId, _id);
- //return Key{ 0x100ULL | sliced, _id };
- }
- [[fallthrough]];
- case Type::Photo:
- return Key{ shifted | sliced | (uint64(_sizeLetter) << 16), _id };
- case Type::Takeout:
- return Key{ shifted, 0 };
- case Type::GroupCallStream:
- return Key{
- (shifted
- | sliced
- | (uint32(_localId) << 16)
- | (_volumeId << 20)
- | (uint64(_sizeLetter) << 56)),
- _id };
- }
- return Key();
- }
- Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
- switch (_type) {
- case Type::Document: {
- const auto high = kDocumentBaseCacheTag
- | ((uint64(_dcId) << 16) & kDocumentBaseCacheMask)
- | (_id >> 48);
- const auto low = (_id << 16);
- Ensures((low & 0x1FFULL) == 0);
- return Storage::Cache::Key{ high, low };
- }
- case Type::StickerSetThumb: {
- const auto high = (uint64(uint32(_localId)) << 24)
- | ((uint64(_type) + 1) << 16)
- | ((uint64(_dcId) & 0xFFULL) << 8)
- | (_volumeId >> 56);
- const auto low = (_volumeId << 8);
- Ensures((low & 0xFFULL) == 0);
- return Storage::Cache::Key{ high, low };
- }
- case Type::Photo: {
- const auto high = kPhotoBaseCacheTag
- | ((uint64(_dcId) << 16) & kPhotoBaseCacheMask)
- | (_id >> 48);
- const auto low = (_id << 16);
- Ensures((low & 0xFFULL) == 0);
- return Storage::Cache::Key{ high, low };
- }
- case Type::Legacy:
- case Type::PeerPhoto:
- case Type::Encrypted:
- case Type::Secure:
- case Type::Takeout:
- case Type::GroupCallStream:
- Unexpected("Not implemented file location type.");
- };
- Unexpected("Invalid file location type.");
- }
- QByteArray StorageFileLocation::fileReference() const {
- return _fileReference;
- }
- bool StorageFileLocation::refreshFileReference(
- const Data::UpdatedFileReferences &updates) {
- const auto i = (_type == Type::Document)
- ? updates.data.find(Data::DocumentFileLocationId{ _id })
- : (_type == Type::Photo)
- ? updates.data.find(Data::PhotoFileLocationId{ _id })
- : end(updates.data);
- return (i != end(updates.data))
- ? refreshFileReference(i->second)
- : false;
- }
- bool StorageFileLocation::refreshFileReference(const QByteArray &data) {
- if (data.isEmpty() || _fileReference == data) {
- return false;
- }
- _fileReference = data;
- return true;
- }
- const StorageFileLocation &StorageFileLocation::Invalid() {
- static auto result = StorageFileLocation();
- return result;
- }
- 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::Legacy:
- 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);
- case Type::GroupCallStream:
- return (a._dcId == b._dcId)
- && (a._id == b._id)
- && (a._localId == b._localId)
- && (a._sizeLetter == b._sizeLetter);
- };
- Unexpected("Type in StorageFileLocation::operator==.");
- }
- bool operator<(const StorageFileLocation &a, const StorageFileLocation &b) {
- const auto valid = a.valid();
- if (valid != b.valid()) {
- return !valid;
- } else if (!valid) {
- return false;
- }
- const auto type = a._type;
- if (type != b._type) {
- return (type < b._type);
- }
- using Type = StorageFileLocation::Type;
- switch (type) {
- case Type::Legacy:
- return std::tie(a._localId, a._volumeId, a._dcId)
- < std::tie(b._localId, b._volumeId, b._dcId);
- case Type::Encrypted:
- case Type::Secure:
- return std::tie(a._id, a._dcId) < std::tie(b._id, b._dcId);
- case Type::Photo:
- case Type::Document:
- return std::tie(a._id, a._dcId, a._sizeLetter)
- < std::tie(b._id, b._dcId, b._sizeLetter);
- case Type::Takeout:
- return false;
- case Type::PeerPhoto:
- return std::tie(
- a._id,
- a._sizeLetter,
- a._localId,
- a._volumeId,
- a._dcId)
- < std::tie(
- b._id,
- b._sizeLetter,
- b._localId,
- b._volumeId,
- b._dcId);
- case Type::StickerSetThumb:
- return std::tie(a._id, a._localId, a._volumeId, a._dcId)
- < std::tie(b._id, b._localId, b._volumeId, b._dcId);
- case Type::GroupCallStream:
- return std::tie(a._id, a._localId, a._dcId, a._sizeLetter)
- < std::tie(b._id, b._localId, b._dcId, b._sizeLetter);
- };
- Unexpected("Type in StorageFileLocation::operator==.");
- }
- InMemoryKey inMemoryKey(const StorageFileLocation &location) {
- const auto key = location.cacheKey();
- return { key.high, key.low };
- }
- 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)));
- return result;
- }
- InMemoryKey inMemoryKey(const GeoPointLocation &location) {
- return InMemoryKey(
- (uint64(base::SafeRound(
- std::abs(location.lat + 360.) * 1000000)) << 32)
- | uint64(base::SafeRound(std::abs(location.lon + 360.) * 1000000)),
- (uint64(location.width) << 32) | uint64(location.height));
- }
- InMemoryKey inMemoryKey(const PlainUrlLocation &location) {
- auto result = InMemoryKey();
- const auto &url = location.url;
- const auto sha = hashSha1(url.data(), url.size() * sizeof(QChar));
- bytes::copy(
- bytes::object_as_span(&result),
- bytes::make_span(sha).subspan(0, sizeof(result)));
- return result;
- }
- InMemoryKey inMemoryKey(const AudioAlbumThumbLocation &location) {
- const auto key = Data::AudioAlbumThumbCacheKey(location);
- return { key.high, key.low };
- }
- InMemoryKey inMemoryKey(const InMemoryLocation &location) {
- auto result = InMemoryKey();
- const auto &data = location.bytes;
- const auto sha = hashSha1(data.data(), data.size());
- bytes::copy(
- bytes::object_as_span(&result),
- bytes::make_span(sha).subspan(0, sizeof(result)));
- return result;
- }
- InMemoryKey inMemoryKey(const DownloadLocation &location) {
- return v::match(location.data, [](const auto &data) {
- return inMemoryKey(data);
- });
- }
- StorageImageLocation::StorageImageLocation(
- const StorageFileLocation &file,
- int width,
- int height)
- : _file(file)
- , _width(width)
- , _height(height) {
- }
- QByteArray StorageImageLocation::serialize() const {
- auto result = _file.serialize();
- if (!result.isEmpty() || (_width > 0) || (_height > 0)) {
- result.reserve(result.size() + 2 * sizeof(qint32));
- auto buffer = QBuffer(&result);
- buffer.open(QIODevice::Append);
- auto stream = QDataStream(&buffer);
- stream.setVersion(QDataStream::Qt_5_1);
- stream << qint32(_width) << qint32(_height);
- }
- return result;
- }
- int StorageImageLocation::serializeSize() const {
- const auto partial = _file.serializeSize();
- return (partial > 0 || _width > 0 || _height > 0)
- ? (partial + 2 * sizeof(qint32))
- : 0;
- }
- std::optional<StorageImageLocation> StorageImageLocation::FromSerialized(
- const QByteArray &serialized) {
- if (const auto file = StorageFileLocation::FromSerialized(serialized)) {
- const auto my = 2 * sizeof(qint32);
- const auto full = serialized.size();
- if (!full) {
- return StorageImageLocation(*file, 0, 0);
- } else if (full >= my) {
- qint32 width = 0;
- qint32 height = 0;
- const auto dimensions = QByteArray::fromRawData(
- serialized.data() + full - my, my);
- auto stream = QDataStream(dimensions);
- stream.setVersion(QDataStream::Qt_5_1);
- stream >> width >> height;
- return (stream.status() == QDataStream::Ok)
- ? StorageImageLocation(*file, width, height)
- : std::optional<StorageImageLocation>();
- }
- }
- return std::nullopt;
- }
- QByteArray DownloadLocation::serialize() const {
- if (!valid() || v::is<StorageFileLocation>(data)) {
- return v::get<StorageFileLocation>(data).serialize();
- }
- auto result = QByteArray();
- auto buffer = QBuffer(&result);
- buffer.open(QIODevice::WriteOnly);
- auto stream = QDataStream(&buffer);
- stream.setVersion(QDataStream::Qt_5_1);
- stream << quint16(0) << kNonStorageLocationToken;
- v::match(data, [&](const StorageFileLocation &data) {
- Unexpected("Variant in DownloadLocation::serialize.");
- }, [&](const WebFileLocation &data) {
- stream
- << quint8(NonStorageLocationType::Web)
- << data.url()
- << quint64(data.accessHash());
- }, [&](const GeoPointLocation &data) {
- stream
- << quint8(NonStorageLocationType::Geo)
- << qreal(data.lat)
- << qreal(data.lon)
- << quint64(data.access)
- << qint32(data.width)
- << qint32(data.height)
- << qint32(data.zoom)
- << qint32(data.scale);
- }, [&](const AudioAlbumThumbLocation &data) {
- stream
- << quint8(NonStorageLocationType::AudioAlbumThumb)
- << quint64(data.documentId);
- }, [&](const PlainUrlLocation &data) {
- stream << quint8(NonStorageLocationType::Url) << data.url.toUtf8();
- }, [&](const InMemoryLocation &data) {
- stream << quint8(NonStorageLocationType::Memory) << data.bytes;
- });
- buffer.close();
- return result;
- }
- int DownloadLocation::serializeSize() const {
- if (!valid() || v::is<StorageFileLocation>(data)) {
- return v::get<StorageFileLocation>(data).serializeSize();
- }
- auto result = sizeof(quint16) + sizeof(quint8) + sizeof(quint8);
- v::match(data, [&](const StorageFileLocation &data) {
- Unexpected("Variant in DownloadLocation::serializeSize.");
- }, [&](const WebFileLocation &data) {
- result += Serialize::bytearraySize(data.url()) + sizeof(quint64);
- }, [&](const GeoPointLocation &data) {
- result += 2 * sizeof(qreal) + sizeof(quint64) + 4 * sizeof(qint32);
- }, [&](const PlainUrlLocation &data) {
- result += Serialize::bytearraySize(data.url.toUtf8());
- }, [&](const AudioAlbumThumbLocation &data) {
- result += sizeof(quint64);
- }, [&](const InMemoryLocation &data) {
- result += Serialize::bytearraySize(data.bytes);
- });
- return result;
- }
- std::optional<DownloadLocation> DownloadLocation::FromSerialized(
- const QByteArray &serialized) {
- quint16 dcId = 0;
- quint8 token = 0;
- auto stream = QDataStream(serialized);
- stream.setVersion(QDataStream::Qt_5_1);
- stream >> dcId >> token;
- if (dcId != 0 || token != kNonStorageLocationToken) {
- const auto storage = StorageFileLocation::FromSerialized(serialized);
- return storage
- ? std::make_optional(DownloadLocation{ *storage })
- : std::nullopt;
- }
- quint8 type = 0;
- stream >> type;
- switch (NonStorageLocationType(type)) {
- case NonStorageLocationType::Web: {
- QByteArray url;
- quint64 accessHash = 0;
- stream >> url >> accessHash;
- return (stream.status() == QDataStream::Ok)
- ? std::make_optional(
- DownloadLocation{ WebFileLocation(url, accessHash) })
- : std::nullopt;
- } break;
- case NonStorageLocationType::Geo: {
- qreal lat = 0.;
- qreal lon = 0.;
- quint64 access = 0;
- qint32 width = 0;
- qint32 height = 0;
- qint32 zoom = 0;
- qint32 scale = 0;
- stream >> lat >> lon >> access >> width >> height >> zoom >> scale;
- return (stream.status() == QDataStream::Ok)
- ? std::make_optional(
- DownloadLocation{ GeoPointLocation{
- .lat = lat,
- .lon = lon,
- .access = access,
- .width = width,
- .height = height,
- .zoom = zoom,
- .scale = scale } })
- : std::nullopt;
- } break;
- case NonStorageLocationType::AudioAlbumThumb: {
- quint64 id = 0;
- stream >> id;
- return (stream.status() == QDataStream::Ok)
- ? std::make_optional(DownloadLocation{
- AudioAlbumThumbLocation{ id } })
- : std::nullopt;
- } break;
- case NonStorageLocationType::Url: {
- QByteArray utf;
- stream >> utf;
- const auto url = base::FromUtf8Safe(utf);
- return (stream.status() == QDataStream::Ok)
- ? std::make_optional(DownloadLocation{ PlainUrlLocation{ url } })
- : std::nullopt;
- } break;
- case NonStorageLocationType::Memory: {
- QByteArray bytes;
- stream >> bytes;
- return (stream.status() == QDataStream::Ok)
- ? std::make_optional(
- DownloadLocation{ InMemoryLocation{ bytes } })
- : std::nullopt;
- } break;
- }
- return std::nullopt;
- }
- DownloadLocation DownloadLocation::convertToModernPeerPhoto(
- uint64 id,
- uint64 accessHash,
- uint64 photoId) const {
- if (!v::is<StorageFileLocation>(data)) {
- return *this;
- }
- auto &file = v::get<StorageFileLocation>(data);
- return DownloadLocation{
- file.convertToModernPeerPhoto(id, accessHash, photoId)
- };
- }
- Storage::Cache::Key DownloadLocation::cacheKey() const {
- return v::match(data, [](const GeoPointLocation &data) {
- return Data::GeoPointCacheKey(data);
- }, [](const StorageFileLocation &data) {
- return data.valid()
- ? data.cacheKey()
- : Storage::Cache::Key();
- }, [](const WebFileLocation &data) {
- return data.isNull()
- ? Storage::Cache::Key()
- : Data::WebDocumentCacheKey(data);
- }, [](const PlainUrlLocation &data) {
- return data.url.isEmpty()
- ? Storage::Cache::Key()
- : Data::UrlCacheKey(data.url);
- }, [](const AudioAlbumThumbLocation &data) {
- return Data::AudioAlbumThumbCacheKey(data);
- }, [](const InMemoryLocation &data) {
- return Storage::Cache::Key();
- });
- }
- Storage::Cache::Key DownloadLocation::bigFileBaseCacheKey() const {
- return v::is<StorageFileLocation>(data)
- ? v::get<StorageFileLocation>(data).bigFileBaseCacheKey()
- : Storage::Cache::Key();
- }
- bool DownloadLocation::valid() const {
- return v::match(data, [](const GeoPointLocation &data) {
- return true;
- }, [](const StorageFileLocation &data) {
- return data.valid();
- }, [](const WebFileLocation &data) {
- return !data.isNull();
- }, [](const PlainUrlLocation &data) {
- return !data.url.isEmpty();
- }, [](const AudioAlbumThumbLocation &data) {
- return data.documentId != 0;
- }, [](const InMemoryLocation &data) {
- return !data.bytes.isEmpty();
- });
- }
- bool DownloadLocation::isLegacy() const {
- return v::is<StorageFileLocation>(data)
- ? v::get<StorageFileLocation>(data).isLegacy()
- : false;
- }
- QByteArray DownloadLocation::fileReference() const {
- if (!v::is<StorageFileLocation>(data)) {
- return QByteArray();
- }
- return v::get<StorageFileLocation>(data).fileReference();
- }
- bool DownloadLocation::refreshFileReference(const QByteArray &data) {
- if (!v::is<StorageFileLocation>(this->data)) {
- return false;
- }
- auto &file = v::get<StorageFileLocation>(this->data);
- return file.refreshFileReference(data);
- }
- bool DownloadLocation::refreshFileReference(
- const Data::UpdatedFileReferences &updates) {
- if (!v::is<StorageFileLocation>(data)) {
- return false;
- }
- auto &file = v::get<StorageFileLocation>(data);
- return file.refreshFileReference(updates);
- }
- ImageLocation::ImageLocation(
- const DownloadLocation &file,
- int width,
- int height)
- : _file(file)
- , _width(width)
- , _height(height) {
- }
- QByteArray ImageLocation::serialize() const {
- auto result = _file.serialize();
- if (!result.isEmpty() || (_width > 0) || (_height > 0)) {
- result.reserve(result.size() + 2 * sizeof(qint32));
- auto buffer = QBuffer(&result);
- buffer.open(QIODevice::Append);
- auto stream = QDataStream(&buffer);
- stream.setVersion(QDataStream::Qt_5_1);
- stream << qint32(_width) << qint32(_height);
- }
- return result;
- }
- int ImageLocation::serializeSize() const {
- const auto partial = _file.serializeSize();
- return (partial > 0 || _width > 0 || _height > 0)
- ? (partial + 2 * sizeof(qint32))
- : 0;
- }
- std::optional<ImageLocation> ImageLocation::FromSerialized(
- const QByteArray &serialized) {
- if (const auto file = DownloadLocation::FromSerialized(serialized)) {
- const auto my = 2 * sizeof(qint32);
- const auto full = serialized.size();
- if (!full) {
- return ImageLocation(*file, 0, 0);
- } else if (full >= my) {
- qint32 width = 0;
- qint32 height = 0;
- const auto dimensions = QByteArray::fromRawData(
- serialized.data() + full - my, my);
- auto stream = QDataStream(dimensions);
- stream.setVersion(QDataStream::Qt_5_1);
- stream >> width >> height;
- return (stream.status() == QDataStream::Ok)
- ? ImageLocation(*file, width, height)
- : std::optional<ImageLocation>();
- }
- }
- return std::nullopt;
- }
|