From 4bb76a7b6f47bf9e0d0d01a72aac579ec73557ee Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 16 Apr 2021 17:43:51 +0300 Subject: [PATCH] Update layer to 128. Remove photo volume_id/local_id. --- td/generate/scheme/telegram_api.tl | 21 ++-- td/telegram/ContactsManager.cpp | 15 +-- td/telegram/FileReferenceManager.cpp | 11 +- td/telegram/MessageContent.cpp | 22 +--- td/telegram/Photo.cpp | 103 +++++++---------- td/telegram/Photo.hpp | 4 + td/telegram/PhotoSizeSource.cpp | 163 +++++++++++++++++++++++++-- td/telegram/PhotoSizeSource.h | 139 +++++++++++++++++++++-- td/telegram/PhotoSizeSource.hpp | 110 +++++++++++++++--- td/telegram/StickersManager.cpp | 4 +- td/telegram/Version.h | 3 +- td/telegram/files/FileDb.cpp | 31 +---- td/telegram/files/FileLocation.h | 85 +++++++++----- td/telegram/files/FileLocation.hpp | 89 +++++++++++++-- td/telegram/files/FileManager.h | 3 +- 15 files changed, 595 insertions(+), 208 deletions(-) diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index 62919c288..814f802ae 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -19,6 +19,9 @@ ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort; accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector = AccessPointRule; help.configSimple#5a592a6c date:int expires:int rules:vector = help.ConfigSimple; +inputPeerPhotoFileLocationLegacy#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; +inputStickerSetThumbLegacy#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; + ---functions--- test.useError = Error; @@ -77,8 +80,8 @@ inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation; -inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation; +inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; +inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; inputGroupCallStream#bba51639 call:InputGroupCall time_ms:long scale:int = InputFileLocation; peerUser#9db1bc6d user_id:int = Peer; @@ -100,7 +103,7 @@ userEmpty#200250ba id:int = User; user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#cc656077 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; +userProfilePhoto#82d1f706 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; userStatusEmpty#9d05049 = UserStatus; userStatusOnline#edb93949 expires:int = UserStatus; @@ -126,7 +129,7 @@ chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0? chatParticipants#3f460fed chat_id:int participants:Vector version:int = ChatParticipants; chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#4790ee05 flags:# has_video:flags.0?true photo_small:FileLocation photo_big:FileLocation stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; +chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; message#bce383d2 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true id:int from_id:flags.8?Peer peer_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector ttl_period:flags.25?int = Message; @@ -182,10 +185,10 @@ photoEmpty#2331b22d id:long = Photo; photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize; -photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; +photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; +photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#5aa86a51 type:string location:FileLocation w:int h:int sizes:Vector = PhotoSize; +photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; geoPointEmpty#1117dd5f = GeoPoint; @@ -1078,8 +1081,6 @@ emojiURL#a575739d url:string = EmojiURL; emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; -fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation; - folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; @@ -1159,7 +1160,7 @@ stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueA help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector users:Vector psa_type:flags.1?string psa_message:flags.2?string = help.PromoData; -videoSize#e831c556 flags:# type:string location:FileLocation w:int h:int size:int video_start_ts:flags.0?double = VideoSize; +videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; statsGroupTopPoster#18f3d0f7 user_id:int messages:int avg_chars:int = StatsGroupTopPoster; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 8b596df0d..d3ecde73e 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -8410,8 +8410,6 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) { int32 flags = telegram_api::user::ACCESS_HASH_MASK | telegram_api::user::FIRST_NAME_MASK | telegram_api::user::APPLY_MIN_PHOTO_MASK; int64 profile_photo_id = 0; - int64 profile_photo_volume_id = 0; - int32 profile_photo_local_id = 0; int32 profile_photo_dc_id = 1; string first_name; string last_name; @@ -8428,8 +8426,6 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) { } phone_number = "42777"; profile_photo_id = 3337190045231023; - profile_photo_volume_id = 107738948; - profile_photo_local_id = 13226; } else if (user_id == get_replies_bot_user_id()) { flags |= telegram_api::user::USERNAME_MASK | telegram_api::user::BOT_MASK; if (!G()->is_test_dc()) { @@ -8447,20 +8443,13 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) { username = G()->is_test_dc() ? "izgroupbot" : "GroupAnonymousBot"; bot_info_version = G()->is_test_dc() ? 1 : 3; profile_photo_id = 5159307831025969322; - profile_photo_volume_id = 806529792; - profile_photo_local_id = 188482; } telegram_api::object_ptr profile_photo; if (!G()->is_test_dc() && profile_photo_id != 0) { flags |= telegram_api::user::PHOTO_MASK; - profile_photo = telegram_api::make_object( - 0, false /*ignored*/, profile_photo_id, - telegram_api::make_object(profile_photo_volume_id, - profile_photo_local_id), - telegram_api::make_object(profile_photo_volume_id, - profile_photo_local_id + 2), - BufferSlice(), profile_photo_dc_id); + profile_photo = telegram_api::make_object(0, false /*ignored*/, profile_photo_id, + BufferSlice(), profile_photo_dc_id); } auto user = telegram_api::make_object( diff --git a/td/telegram/FileReferenceManager.cpp b/td/telegram/FileReferenceManager.cpp index dbec96cae..b85a5107d 100644 --- a/td/telegram/FileReferenceManager.cpp +++ b/td/telegram/FileReferenceManager.cpp @@ -354,16 +354,25 @@ void FileReferenceManager::reload_photo(PhotoSizeSource source, Promise pr switch (source.get_type()) { case PhotoSizeSource::Type::DialogPhotoBig: case PhotoSizeSource::Type::DialogPhotoSmall: + case PhotoSizeSource::Type::DialogPhotoBigLegacy: + case PhotoSizeSource::Type::DialogPhotoSmallLegacy: send_closure(G()->contacts_manager(), &ContactsManager::reload_dialog_info, source.dialog_photo().dialog_id, std::move(promise)); break; case PhotoSizeSource::Type::StickerSetThumbnail: + case PhotoSizeSource::Type::StickerSetThumbnailLegacy: + case PhotoSizeSource::Type::StickerSetThumbnailVersion: send_closure(G()->stickers_manager(), &StickersManager::reload_sticker_set, StickerSetId(source.sticker_set_thumbnail().sticker_set_id), source.sticker_set_thumbnail().sticker_set_access_hash, std::move(promise)); break; - default: + case PhotoSizeSource::Type::Legacy: + case PhotoSizeSource::Type::FullLegacy: + case PhotoSizeSource::Type::Thumbnail: promise.set_error(Status::Error("Unexpected PhotoSizeSource type")); + break; + default: + UNREACHABLE(); } } diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index b9fdb0d9e..bf770e8ac 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -3091,10 +3091,9 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo new_file_view.remote_location().get_file_reference() || old_file_view.main_remote_location().get_access_hash() != new_file_view.remote_location().get_access_hash()) { - auto volume_id = -new_file_view.remote_location().get_id(); FileId file_id = td->file_manager_->register_remote( FullRemoteFileLocation({FileType::Photo, 'i'}, new_file_view.remote_location().get_id(), - new_file_view.remote_location().get_access_hash(), 0, volume_id, DcId::invalid(), + new_file_view.remote_location().get_access_hash(), DcId::invalid(), new_file_view.remote_location().get_file_reference().str()), FileLocationSource::FromServer, dialog_id, old_photo->photos.back().size, 0, ""); LOG_STATUS(td->file_manager_->merge(file_id, old_file_id)); @@ -3592,16 +3591,6 @@ void unregister_message_content(Td *td, const MessageContent *content, FullMessa template static tl_object_ptr secret_to_telegram(FromT &from); -// fileLocationUnavailable volume_id:long local_id:int secret:long = FileLocation; -static auto secret_to_telegram(secret_api::fileLocationUnavailable &file_location) { - return make_tl_object(file_location.volume_id_, file_location.local_id_); -} - -// fileLocation dc_id:int volume_id:long local_id:int secret:long = FileLocation; -static auto secret_to_telegram(secret_api::fileLocation &file_location) { - return make_tl_object(file_location.volume_id_, file_location.local_id_); -} - // photoSizeEmpty type:string = PhotoSize; static auto secret_to_telegram(secret_api::photoSizeEmpty &empty) { if (!clean_input_string(empty.type_)) { @@ -3615,9 +3604,7 @@ static auto secret_to_telegram(secret_api::photoSize &photo_size) { if (!clean_input_string(photo_size.type_)) { photo_size.type_.clear(); } - return make_tl_object( - photo_size.type_, secret_to_telegram(*photo_size.location_), - photo_size.w_, photo_size.h_, photo_size.size_); + return make_tl_object(photo_size.type_, photo_size.w_, photo_size.h_, photo_size.size_); } // photoCachedSize type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize; @@ -3625,9 +3612,8 @@ static auto secret_to_telegram(secret_api::photoCachedSize &photo_size) { if (!clean_input_string(photo_size.type_)) { photo_size.type_.clear(); } - return make_tl_object( - photo_size.type_, secret_to_telegram(*photo_size.location_), - photo_size.w_, photo_size.h_, photo_size.bytes_.clone()); + return make_tl_object(photo_size.type_, photo_size.w_, photo_size.h_, + photo_size.bytes_.clone()); } // documentAttributeImageSize w:int h:int = DocumentAttribute; diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 01de1e489..72283a7ed 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -139,20 +139,15 @@ static StringBuilder &operator<<(StringBuilder &string_builder, PhotoFormat form } static FileId register_photo(FileManager *file_manager, const PhotoSizeSource &source, int64 id, int64 access_hash, - std::string file_reference, - tl_object_ptr &&location, - DialogId owner_dialog_id, int32 file_size, DcId dc_id, PhotoFormat format) { - int32 local_id = location->local_id_; - int64 volume_id = location->volume_id_; - LOG(DEBUG) << "Receive " << format << " photo of type " << source.get_file_type() << " in [" << dc_id << "," - << volume_id << "," << local_id << "]. Id: (" << id << ", " << access_hash << ")"; - auto suggested_name = PSTRING() << static_cast(volume_id) << "_" << static_cast(local_id) << '.' - << format; + std::string file_reference, DialogId owner_dialog_id, int32 file_size, DcId dc_id, + PhotoFormat format) { + LOG(DEBUG) << "Receive " << format << " photo " << id << " of type " << source.get_file_type() << " from " << dc_id; + auto suggested_name = PSTRING() << source.get_unique_name(id) << '.' << format; auto file_location_source = owner_dialog_id.get_type() == DialogType::SecretChat ? FileLocationSource::FromUser : FileLocationSource::FromServer; return file_manager->register_remote( - FullRemoteFileLocation(source, id, access_hash, local_id, volume_id, dc_id, std::move(file_reference)), - file_location_source, owner_dialog_id, file_size, 0, std::move(suggested_name)); + FullRemoteFileLocation(source, id, access_hash, dc_id, std::move(file_reference)), file_location_source, + owner_dialog_id, file_size, 0, std::move(suggested_name)); } ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64 user_access_hash, @@ -171,11 +166,11 @@ ProfilePhoto get_profile_photo(FileManager *file_manager, UserId user_id, int64 result.id = profile_photo->photo_id_; result.minithumbnail = profile_photo->stripped_thumb_.as_slice().str(); result.small_file_id = - register_photo(file_manager, {DialogId(user_id), user_access_hash, false}, result.id, 0, "", - std::move(profile_photo->photo_small_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); + register_photo(file_manager, {DialogId(user_id), user_access_hash, false}, result.id, 0 /*access_hash*/, + "" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg); result.big_file_id = - register_photo(file_manager, {DialogId(user_id), user_access_hash, true}, result.id, 0, "", - std::move(profile_photo->photo_big_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); + register_photo(file_manager, {DialogId(user_id), user_access_hash, true}, result.id, 0 /*access_hash*/, + "" /*file_reference*/, DialogId(), 0 /*file_size*/, dc_id, PhotoFormat::Jpeg); break; } default: @@ -199,17 +194,9 @@ tl_object_ptr get_profile_photo_object(FileManager *file_m bool operator==(const ProfilePhoto &lhs, const ProfilePhoto &rhs) { bool location_differs = lhs.small_file_id != rhs.small_file_id || lhs.big_file_id != rhs.big_file_id; - bool id_differs; - if (lhs.id == -1 && rhs.id == -1) { - // group chat photo - id_differs = location_differs; - } else { - id_differs = lhs.id != rhs.id; - } + bool id_differs = lhs.id != rhs.id; if (location_differs) { - LOG_IF(ERROR, !id_differs) << "Photo " << lhs.id << " location has changed. First profilePhoto: " << lhs - << ", second profilePhoto: " << rhs; return false; } return lhs.has_animation == rhs.has_animation && lhs.minithumbnail == rhs.minithumbnail && !id_differs; @@ -239,11 +226,10 @@ DialogPhoto get_dialog_photo(FileManager *file_manager, DialogId dialog_id, int6 auto dc_id = DcId::create(chat_photo->dc_id_); result.has_animation = (chat_photo->flags_ & telegram_api::chatPhoto::HAS_VIDEO_MASK) != 0; result.minithumbnail = chat_photo->stripped_thumb_.as_slice().str(); - result.small_file_id = - register_photo(file_manager, {dialog_id, dialog_access_hash, false}, 0, 0, "", - std::move(chat_photo->photo_small_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); - result.big_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, true}, 0, 0, "", - std::move(chat_photo->photo_big_), DialogId(), 0, dc_id, PhotoFormat::Jpeg); + result.small_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, false}, chat_photo->photo_id_, + 0, "", DialogId(), 0, dc_id, PhotoFormat::Jpeg); + result.big_file_id = register_photo(file_manager, {dialog_id, dialog_access_hash, true}, chat_photo->photo_id_, 0, + "", DialogId(), 0, dc_id, PhotoFormat::Jpeg); break; } @@ -287,6 +273,7 @@ DialogPhoto as_fake_dialog_photo(const Photo &photo) { result.big_file_id = size.file_id; } } + result.minithumbnail = photo.minithumbnail; result.has_animation = !photo.animations.empty(); if (!result.small_file_id.is_valid() || !result.big_file_id.is_valid()) { LOG(ERROR) << "Failed to convert " << photo << " to chat photo"; @@ -348,14 +335,12 @@ PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice // generate some random remote location to save auto dc_id = DcId::invalid(); - auto local_id = -(Random::secure_int32() & 0x7FFFFFFF); - auto volume_id = Random::secure_int64(); + auto photo_id = -(Random::secure_int64() & std::numeric_limits::max()); res.file_id = file_manager->register_remote( - FullRemoteFileLocation(PhotoSizeSource(FileType::EncryptedThumbnail, 't'), 0, 0, local_id, volume_id, dc_id, - string()), + FullRemoteFileLocation(PhotoSizeSource(FileType::EncryptedThumbnail, 't'), photo_id, 0, dc_id, string()), FileLocationSource::FromServer, owner_dialog_id, res.size, 0, - PSTRING() << static_cast(volume_id) << "_" << static_cast(local_id) << ".jpg"); + PSTRING() << static_cast(photo_id) << ".jpg"); file_manager->set_content(res.file_id, std::move(bytes)); return res; @@ -367,7 +352,6 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo PhotoFormat format) { CHECK(size_ptr != nullptr); - tl_object_ptr location; string type; PhotoSize res; BufferSlice content; @@ -378,7 +362,6 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo auto size = move_tl_object_as(size_ptr); type = std::move(size->type_); - location = std::move(size->location_); res.dimensions = get_dimensions(size->w_, size->h_, "photoSize"); res.size = size->size_; @@ -388,7 +371,6 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo auto size = move_tl_object_as(size_ptr); type = std::move(size->type_); - location = std::move(size->location_); CHECK(size->bytes_.size() <= static_cast(std::numeric_limits::max())); res.dimensions = get_dimensions(size->w_, size->h_, "photoCachedSize"); res.size = static_cast(size->bytes_.size()); @@ -415,7 +397,6 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo std::sort(size->sizes_.begin(), size->sizes_.end()); type = std::move(size->type_); - location = std::move(size->location_); res.dimensions = get_dimensions(size->w_, size->h_, "photoSizeProgressive"); res.size = size->sizes_.back(); size->sizes_.pop_back(); @@ -437,17 +418,21 @@ Variant get_photo_size(FileManager *file_manager, PhotoSizeSo } if (type.size() != 1) { - res.type = 0; LOG(ERROR) << "Wrong photoSize \"" << type << "\" " << res; + res.type = 0; } else { res.type = static_cast(type[0]); + if (res.type >= 128) { + LOG(ERROR) << "Wrong photoSize \"" << type << "\" " << res; + res.type = 0; + } } if (source.get_type() == PhotoSizeSource::Type::Thumbnail) { source.thumbnail().thumbnail_type = res.type; } - res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, std::move(location), - owner_dialog_id, res.size, dc_id, format); + res.file_id = + register_photo(file_manager, source, id, access_hash, file_reference, owner_dialog_id, res.size, dc_id, format); if (!content.empty()) { file_manager->set_content(res.file_id, std::move(content)); @@ -465,6 +450,10 @@ AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource sour LOG(ERROR) << "Wrong videoSize \"" << size->type_ << "\" in " << to_string(size); } res.type = static_cast(size->type_[0]); + if (res.type >= 128) { + LOG(ERROR) << "Wrong videoSize \"" << res.type << "\" " << res; + res.type = 0; + } res.dimensions = get_dimensions(size->w_, size->h_, "get_animation_size"); res.size = size->size_; if ((size->flags_ & telegram_api::videoSize::VIDEO_START_TS_MASK) != 0) { @@ -475,8 +464,8 @@ AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource sour source.thumbnail().thumbnail_type = res.type; } - res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, std::move(size->location_), - owner_dialog_id, res.size, dc_id, PhotoFormat::Mpeg4); + res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, owner_dialog_id, res.size, dc_id, + PhotoFormat::Mpeg4); return res; } @@ -937,20 +926,14 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Photo &photo) { return string_builder << ']'; } -static tl_object_ptr copy_location( - const tl_object_ptr &location) { - CHECK(location != nullptr); - return make_tl_object(location->volume_id_, location->local_id_); -} - tl_object_ptr convert_photo_to_profile_photo( const tl_object_ptr &photo) { if (photo == nullptr) { return nullptr; } - tl_object_ptr photo_small; - tl_object_ptr photo_big; + bool have_photo_small = false; + bool have_photo_big = false; for (auto &size_ptr : photo->sizes_) { switch (size_ptr->get_id()) { case telegram_api::photoSizeEmpty::ID: @@ -958,18 +941,18 @@ tl_object_ptr convert_photo_to_profile_photo( case telegram_api::photoSize::ID: { auto size = static_cast(size_ptr.get()); if (size->type_ == "a") { - photo_small = copy_location(size->location_); + have_photo_small = true; } else if (size->type_ == "c") { - photo_big = copy_location(size->location_); + have_photo_big = true; } break; } case telegram_api::photoCachedSize::ID: { auto size = static_cast(size_ptr.get()); if (size->type_ == "a") { - photo_small = copy_location(size->location_); + have_photo_small = true; } else if (size->type_ == "c") { - photo_big = copy_location(size->location_); + have_photo_big = true; } break; } @@ -978,9 +961,9 @@ tl_object_ptr convert_photo_to_profile_photo( case telegram_api::photoSizeProgressive::ID: { auto size = static_cast(size_ptr.get()); if (size->type_ == "a") { - photo_small = copy_location(size->location_); + have_photo_small = true; } else if (size->type_ == "c") { - photo_big = copy_location(size->location_); + have_photo_big = true; } break; } @@ -989,15 +972,15 @@ tl_object_ptr convert_photo_to_profile_photo( break; } } - if (photo_small == nullptr || photo_big == nullptr) { + if (!have_photo_small || !have_photo_big) { return nullptr; } int32 flags = 0; if (!photo->video_sizes_.empty()) { flags |= telegram_api::userProfilePhoto::HAS_VIDEO_MASK; } - return make_tl_object(flags, false /*ignored*/, photo->id_, std::move(photo_small), - std::move(photo_big), BufferSlice(), photo->dc_id_); + return make_tl_object(flags, false /*ignored*/, photo->id_, BufferSlice(), + photo->dc_id_); } } // namespace td diff --git a/td/telegram/Photo.hpp b/td/telegram/Photo.hpp index 8289a7d5c..f06483ea2 100644 --- a/td/telegram/Photo.hpp +++ b/td/telegram/Photo.hpp @@ -99,6 +99,10 @@ void parse(PhotoSize &photo_size, ParserT &parser) { } else { photo_size.progressive_sizes.clear(); } + if (photo_size.type < 0 || photo_size.type >= 128) { + parser.set_error("Wrong PhotoSize type"); + return; + } LOG(DEBUG) << "Parsed photo size " << photo_size; } diff --git a/td/telegram/PhotoSizeSource.cpp b/td/telegram/PhotoSizeSource.cpp index 5d0d791a1..42056573b 100644 --- a/td/telegram/PhotoSizeSource.cpp +++ b/td/telegram/PhotoSizeSource.cpp @@ -11,6 +11,9 @@ #include "td/telegram/UserId.h" #include "td/utils/common.h" +#include "td/utils/StackAllocator.h" +#include "td/utils/tl_helpers.h" +#include "td/utils/tl_storers.h" namespace td { @@ -40,22 +43,117 @@ tl_object_ptr PhotoSizeSource::DialogPhoto::get_input_p FileType PhotoSizeSource::get_file_type() const { switch (get_type()) { - case PhotoSizeSource::Type::Thumbnail: + case Type::Thumbnail: return thumbnail().file_type; - case PhotoSizeSource::Type::DialogPhotoSmall: - case PhotoSizeSource::Type::DialogPhotoBig: + case Type::DialogPhotoSmall: + case Type::DialogPhotoBig: + case Type::DialogPhotoSmallLegacy: + case Type::DialogPhotoBigLegacy: return FileType::ProfilePhoto; - case PhotoSizeSource::Type::StickerSetThumbnail: + case Type::StickerSetThumbnail: + case Type::StickerSetThumbnailLegacy: + case Type::StickerSetThumbnailVersion: return FileType::Thumbnail; - case PhotoSizeSource::Type::Legacy: + case Type::Legacy: + case Type::FullLegacy: default: UNREACHABLE(); return FileType::Thumbnail; } } +string PhotoSizeSource::get_unique() const { + auto ptr = StackAllocator::alloc(16); + MutableSlice data = ptr.as_slice(); + TlStorerUnsafe storer(data.ubegin()); + switch (get_type()) { + case Type::Legacy: + UNREACHABLE(); + break; + case Type::Thumbnail: { + auto type = thumbnail().thumbnail_type; + CHECK(0 <= type && type <= 127); + if (type == 'a') { + type = 0; + } else if (type == 'c') { + type = 1; + } else { + type += 5; + } + return string(1, static_cast(type)); + } + case Type::DialogPhotoSmall: + // it doesn't matter to which Dialog the photo belongs + return string(1, '\x00'); + case Type::DialogPhotoBig: + // it doesn't matter to which Dialog the photo belongs + return string(1, '\x01'); + case Type::StickerSetThumbnail: + UNREACHABLE(); + break; + case Type::FullLegacy: { + auto &legacy = full_legacy(); + td::store(legacy.volume_id, storer); + td::store(legacy.local_id, storer); + break; + } + case Type::DialogPhotoSmallLegacy: + case Type::DialogPhotoBigLegacy: { + auto &legacy = dialog_photo_legacy(); + td::store(legacy.volume_id, storer); + td::store(legacy.local_id, storer); + break; + } + case Type::StickerSetThumbnailLegacy: { + auto &legacy = sticker_set_thumbnail_legacy(); + td::store(legacy.volume_id, storer); + td::store(legacy.local_id, storer); + break; + } + case Type::StickerSetThumbnailVersion: { + auto &thumbnail = sticker_set_thumbnail_version(); + storer.store_slice(Slice("\x02")); + td::store(thumbnail.sticker_set_id, storer); + td::store(thumbnail.version, storer); + break; + } + default: + UNREACHABLE(); + break; + } + auto size = storer.get_buf() - data.ubegin(); + CHECK(size <= 13); + return string(data.begin(), size); +} + +string PhotoSizeSource::get_unique_name(int64 photo_id) const { + switch (get_type()) { + case Type::Thumbnail: + CHECK(0 <= thumbnail().thumbnail_type && thumbnail().thumbnail_type <= 127); + return PSTRING() << photo_id << '_' << thumbnail().thumbnail_type; + case Type::DialogPhotoSmall: + return to_string(photo_id); + case Type::DialogPhotoBig: + return PSTRING() << photo_id << '_' << 1; + case Type::StickerSetThumbnailVersion: + return PSTRING() << sticker_set_thumbnail_version().sticker_set_id << '_' + << static_cast(sticker_set_thumbnail_version().version); + case Type::Legacy: + case Type::StickerSetThumbnail: + case Type::FullLegacy: + case Type::DialogPhotoSmallLegacy: + case Type::DialogPhotoBigLegacy: + case Type::StickerSetThumbnailLegacy: + default: + UNREACHABLE(); + break; + } + return 0; +} + static bool operator==(const PhotoSizeSource::Legacy &lhs, const PhotoSizeSource::Legacy &rhs) { - return lhs.secret == rhs.secret; + UNREACHABLE(); + return false; } static bool operator==(const PhotoSizeSource::Thumbnail &lhs, const PhotoSizeSource::Thumbnail &rhs) { @@ -81,6 +179,42 @@ static bool operator==(const PhotoSizeSource::StickerSetThumbnail &lhs, return lhs.sticker_set_id == rhs.sticker_set_id && lhs.sticker_set_access_hash == rhs.sticker_set_access_hash; } +static bool operator==(const PhotoSizeSource::FullLegacy &lhs, const PhotoSizeSource::FullLegacy &rhs) { + return lhs.volume_id == rhs.volume_id && lhs.local_id == rhs.local_id && lhs.secret == rhs.secret; +} + +static bool operator==(const PhotoSizeSource::DialogPhotoLegacy &lhs, const PhotoSizeSource::DialogPhotoLegacy &rhs) { + return static_cast(lhs) == + static_cast(rhs) && + lhs.volume_id == rhs.volume_id && lhs.local_id == rhs.local_id; +} + +static bool operator==(const PhotoSizeSource::DialogPhotoSmallLegacy &lhs, + const PhotoSizeSource::DialogPhotoSmallLegacy &rhs) { + return static_cast(lhs) == + static_cast(rhs); +} + +static bool operator==(const PhotoSizeSource::DialogPhotoBigLegacy &lhs, + const PhotoSizeSource::DialogPhotoBigLegacy &rhs) { + return static_cast(lhs) == + static_cast(rhs); +} + +static bool operator==(const PhotoSizeSource::StickerSetThumbnailLegacy &lhs, + const PhotoSizeSource::StickerSetThumbnailLegacy &rhs) { + return static_cast(lhs) == + static_cast(rhs) && + lhs.volume_id == rhs.volume_id && lhs.local_id == rhs.local_id; +} + +static bool operator==(const PhotoSizeSource::StickerSetThumbnailVersion &lhs, + const PhotoSizeSource::StickerSetThumbnailVersion &rhs) { + return static_cast(lhs) == + static_cast(rhs) && + lhs.version == rhs.version; +} + bool operator==(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs) { return lhs.variant == rhs.variant; } @@ -91,6 +225,8 @@ bool operator!=(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs) { StringBuilder &operator<<(StringBuilder &string_builder, const PhotoSizeSource &source) { switch (source.get_type()) { + case PhotoSizeSource::Type::Legacy: + return string_builder << "PhotoSizeSourceLegacy[]"; case PhotoSizeSource::Type::Thumbnail: return string_builder << "PhotoSizeSourceThumbnail[" << source.thumbnail().file_type << ", type = " << source.thumbnail().thumbnail_type << ']'; @@ -101,8 +237,19 @@ StringBuilder &operator<<(StringBuilder &string_builder, const PhotoSizeSource & case PhotoSizeSource::Type::StickerSetThumbnail: return string_builder << "PhotoSizeSourceStickerSetThumbnail[" << source.sticker_set_thumbnail().sticker_set_id << ']'; - case PhotoSizeSource::Type::Legacy: - return string_builder << "PhotoSizeSourceLegacy[]"; + case PhotoSizeSource::Type::FullLegacy: + return string_builder << "PhotoSizeSourceFullLegacy[]"; + case PhotoSizeSource::Type::DialogPhotoSmallLegacy: + return string_builder << "PhotoSizeSourceChatPhotoSmallLegacy[" << source.dialog_photo().dialog_id << ']'; + case PhotoSizeSource::Type::DialogPhotoBigLegacy: + return string_builder << "PhotoSizeSourceChatPhotoBigLegacy[" << source.dialog_photo().dialog_id << ']'; + case PhotoSizeSource::Type::StickerSetThumbnailLegacy: + return string_builder << "PhotoSizeSourceStickerSetThumbnailLegacy[" + << source.sticker_set_thumbnail().sticker_set_id << ']'; + case PhotoSizeSource::Type::StickerSetThumbnailVersion: + return string_builder << "PhotoSizeSourceStickerSetThumbnailVersion[" + << source.sticker_set_thumbnail().sticker_set_id << '_' + << source.sticker_set_thumbnail_version().version << ']'; default: UNREACHABLE(); return string_builder; diff --git a/td/telegram/PhotoSizeSource.h b/td/telegram/PhotoSizeSource.h index 8be13e258..baf801b72 100644 --- a/td/telegram/PhotoSizeSource.h +++ b/td/telegram/PhotoSizeSource.h @@ -15,10 +15,23 @@ #include "td/utils/StringBuilder.h" #include "td/utils/Variant.h" +#include + namespace td { struct PhotoSizeSource { - enum class Type : int32 { Legacy, Thumbnail, DialogPhotoSmall, DialogPhotoBig, StickerSetThumbnail }; + enum class Type : int32 { + Legacy, + Thumbnail, + DialogPhotoSmall, + DialogPhotoBig, + StickerSetThumbnail, + FullLegacy, + DialogPhotoSmallLegacy, + DialogPhotoBigLegacy, + StickerSetThumbnailLegacy, + StickerSetThumbnailVersion + }; // for legacy photos with secret struct Legacy { @@ -75,9 +88,59 @@ struct PhotoSizeSource { } }; + // for legacy photos with volume_id, local_id, secret + struct FullLegacy { + FullLegacy() = default; + FullLegacy(int64 volume_id, int32 local_id, int64 secret) + : volume_id(volume_id), local_id(local_id), secret(secret) { + } + + int64 volume_id = 0; + int32 local_id = 0; + int64 secret = 0; + }; + + // for legacy dialog photos + struct DialogPhotoLegacy : public DialogPhoto { + DialogPhotoLegacy() = default; + DialogPhotoLegacy(DialogId dialog_id, int64 dialog_access_hash, int64 volume_id, int32 local_id) + : DialogPhoto(dialog_id, dialog_access_hash), volume_id(volume_id), local_id(local_id) { + } + + int64 volume_id = 0; + int32 local_id = 0; + }; + + struct DialogPhotoSmallLegacy : public DialogPhotoLegacy { + using DialogPhotoLegacy::DialogPhotoLegacy; + }; + + struct DialogPhotoBigLegacy : public DialogPhotoLegacy { + using DialogPhotoLegacy::DialogPhotoLegacy; + }; + + // for legacy sticker set thumbnails + struct StickerSetThumbnailLegacy : public StickerSetThumbnail { + StickerSetThumbnailLegacy() = default; + StickerSetThumbnailLegacy(int64 sticker_set_id, int64 sticker_set_access_hash, int64 volume_id, int32 local_id) + : StickerSetThumbnail(sticker_set_id, sticker_set_access_hash), volume_id(volume_id), local_id(local_id) { + } + + int64 volume_id = 0; + int32 local_id = 0; + }; + + // for sticker set thumbnails identified by version + struct StickerSetThumbnailVersion : public StickerSetThumbnail { + StickerSetThumbnailVersion() = default; + StickerSetThumbnailVersion(int64 sticker_set_id, int64 sticker_set_access_hash, int32 version) + : StickerSetThumbnail(sticker_set_id, sticker_set_access_hash), version(version) { + } + + int32 version = 0; + }; + PhotoSizeSource() = default; - explicit PhotoSizeSource(int64 secret) : variant(Legacy(secret)) { - } PhotoSizeSource(FileType file_type, int32 thumbnail_type) : variant(Thumbnail(file_type, thumbnail_type)) { } PhotoSizeSource(DialogId dialog_id, int64 dialog_access_hash, bool is_big) { @@ -90,6 +153,22 @@ struct PhotoSizeSource { PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash) : variant(StickerSetThumbnail(sticker_set_id, sticker_set_access_hash)) { } + PhotoSizeSource(std::nullptr_t, int64 volume_id, int32 local_id, int64 secret) + : variant(FullLegacy(volume_id, local_id, secret)) { + } + PhotoSizeSource(DialogId dialog_id, int64 dialog_access_hash, bool is_big, int64 volume_id, int32 local_id) { + if (is_big) { + variant = DialogPhotoBigLegacy(dialog_id, dialog_access_hash, volume_id, local_id); + } else { + variant = DialogPhotoSmallLegacy(dialog_id, dialog_access_hash, volume_id, local_id); + } + } + PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash, int64 volume_id, int32 local_id) + : variant(StickerSetThumbnailLegacy(sticker_set_id, sticker_set_access_hash, volume_id, local_id)) { + } + PhotoSizeSource(int64 sticker_set_id, int64 sticker_set_access_hash, int32 version) + : variant(StickerSetThumbnailVersion(sticker_set_id, sticker_set_access_hash, version)) { + } Type get_type() const { auto offset = variant.get_offset(); @@ -110,15 +189,55 @@ struct PhotoSizeSource { return variant.get(); } const DialogPhoto &dialog_photo() const { - if (variant.get_offset() == 2) { - return variant.get(); - } else { - return variant.get(); + switch (variant.get_offset()) { + case 2: + return variant.get(); + case 3: + return variant.get(); + case 6: + return variant.get(); + case 7: + return variant.get(); + default: + UNREACHABLE(); + return variant.get(); } } const StickerSetThumbnail &sticker_set_thumbnail() const { - return variant.get(); + switch (variant.get_offset()) { + case 4: + return variant.get(); + case 8: + return variant.get(); + case 9: + return variant.get(); + default: + UNREACHABLE(); + return variant.get(); + } } + const FullLegacy &full_legacy() const { + return variant.get(); + } + const DialogPhotoLegacy &dialog_photo_legacy() const { + if (variant.get_offset() == 6) { + return variant.get(); + } else { + return variant.get(); + } + } + const StickerSetThumbnailLegacy &sticker_set_thumbnail_legacy() const { + return variant.get(); + } + const StickerSetThumbnailVersion &sticker_set_thumbnail_version() const { + return variant.get(); + } + + // returns unique representation of the source + string get_unique() const; + + // can't be called for Legacy sources + string get_unique_name(int64 photo_id) const; template void store(StorerT &storer) const; @@ -128,7 +247,9 @@ struct PhotoSizeSource { friend bool operator==(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs); private: - Variant variant; + Variant + variant; }; bool operator==(const PhotoSizeSource &lhs, const PhotoSizeSource &rhs); diff --git a/td/telegram/PhotoSizeSource.hpp b/td/telegram/PhotoSizeSource.hpp index 84be3dae2..fb3c952a1 100644 --- a/td/telegram/PhotoSizeSource.hpp +++ b/td/telegram/PhotoSizeSource.hpp @@ -15,6 +15,7 @@ namespace td { template void store(const PhotoSizeSource::Legacy &source, StorerT &storer) { + UNREACHABLE(); store(source.secret, storer); } @@ -39,23 +40,11 @@ void parse(PhotoSizeSource::Thumbnail &source, ParserT &parser) { source.file_type = static_cast(raw_type); parse(source.thumbnail_type, parser); - if (source.thumbnail_type < 0 || source.thumbnail_type > 255) { + if (source.thumbnail_type < 0 || source.thumbnail_type > 127) { parser.set_error("Wrong thumbnail type"); } } -template -void store(const PhotoSizeSource::StickerSetThumbnail &source, StorerT &storer) { - store(source.sticker_set_id, storer); - store(source.sticker_set_access_hash, storer); -} - -template -void parse(PhotoSizeSource::StickerSetThumbnail &source, ParserT &parser) { - parse(source.sticker_set_id, parser); - parse(source.sticker_set_access_hash, parser); -} - template void store(const PhotoSizeSource::DialogPhoto &source, StorerT &storer) { store(source.dialog_id, storer); @@ -96,6 +85,101 @@ void parse(PhotoSizeSource::DialogPhotoBig &source, ParserT &parser) { parse(static_cast(source), parser); } +template +void store(const PhotoSizeSource::StickerSetThumbnail &source, StorerT &storer) { + store(source.sticker_set_id, storer); + store(source.sticker_set_access_hash, storer); +} + +template +void parse(PhotoSizeSource::StickerSetThumbnail &source, ParserT &parser) { + parse(source.sticker_set_id, parser); + parse(source.sticker_set_access_hash, parser); +} + +template +void store(const PhotoSizeSource::FullLegacy &source, StorerT &storer) { + store(source.volume_id, storer); + store(source.secret, storer); + store(source.local_id, storer); +} + +template +void parse(PhotoSizeSource::FullLegacy &source, ParserT &parser) { + parse(source.volume_id, parser); + parse(source.secret, parser); + parse(source.local_id, parser); + if (source.local_id < 0) { + parser.set_error("Wrong local_id"); + } +} + +template +void store(const PhotoSizeSource::DialogPhotoLegacy &source, StorerT &storer) { + store(static_cast(source), storer); + store(source.volume_id, storer); + store(source.local_id, storer); +} + +template +void parse(PhotoSizeSource::DialogPhotoLegacy &source, ParserT &parser) { + parse(static_cast(source), parser); + parse(source.volume_id, parser); + parse(source.local_id, parser); + if (source.local_id < 0) { + parser.set_error("Wrong local_id"); + } +} + +template +void store(const PhotoSizeSource::DialogPhotoSmallLegacy &source, StorerT &storer) { + store(static_cast(source), storer); +} + +template +void parse(PhotoSizeSource::DialogPhotoSmallLegacy &source, ParserT &parser) { + parse(static_cast(source), parser); +} + +template +void store(const PhotoSizeSource::DialogPhotoBigLegacy &source, StorerT &storer) { + store(static_cast(source), storer); +} + +template +void parse(PhotoSizeSource::DialogPhotoBigLegacy &source, ParserT &parser) { + parse(static_cast(source), parser); +} + +template +void store(const PhotoSizeSource::StickerSetThumbnailLegacy &source, StorerT &storer) { + store(static_cast(source), storer); + store(source.volume_id, storer); + store(source.local_id, storer); +} + +template +void parse(PhotoSizeSource::StickerSetThumbnailLegacy &source, ParserT &parser) { + parse(static_cast(source), parser); + parse(source.volume_id, parser); + parse(source.local_id, parser); + if (source.local_id < 0) { + parser.set_error("Wrong local_id"); + } +} + +template +void store(const PhotoSizeSource::StickerSetThumbnailVersion &source, StorerT &storer) { + store(static_cast(source), storer); + store(source.version, storer); +} + +template +void parse(PhotoSizeSource::StickerSetThumbnailVersion &source, ParserT &parser) { + parse(static_cast(source), parser); + parse(source.version, parser); +} + template void PhotoSizeSource::store(StorerT &storer) const { td::store(variant, storer); diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 5faad9c60..7c0e5449b 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -2445,8 +2445,8 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptrthumbs_) { - auto photo_size = get_photo_size(td_->file_manager_.get(), {set_id.get(), s->access_hash}, 0, 0, "", - DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb), + auto photo_size = get_photo_size(td_->file_manager_.get(), {set_id.get(), s->access_hash, set->thumb_version_}, 0, + 0, "", DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb), is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp); if (photo_size.get_offset() == 0) { if (!thumbnail.file_id.is_valid()) { diff --git a/td/telegram/Version.h b/td/telegram/Version.h index a523cd6cc..14ebb415f 100644 --- a/td/telegram/Version.h +++ b/td/telegram/Version.h @@ -8,7 +8,7 @@ namespace td { -constexpr int32 MTPROTO_LAYER = 127; +constexpr int32 MTPROTO_LAYER = 128; enum class Version : int32 { Initial, // 0 @@ -43,6 +43,7 @@ enum class Version : int32 { AddLiveLocationHeading, AddLiveLocationProximityAlertDistance, // 30 SupportBannedChannels, + RemovePhotoVolumeAndLocalId, Next }; diff --git a/td/telegram/files/FileDb.cpp b/td/telegram/files/FileDb.cpp index 869c571e4..2fd02e5dc 100644 --- a/td/telegram/files/FileDb.cpp +++ b/td/telegram/files/FileDb.cpp @@ -40,7 +40,6 @@ Status drop_file_db(SqliteDb &db, int32 version) { return Status::OK(); } -Status fix_file_remote_location_key_bug(SqliteDb &db); Status init_file_db(SqliteDb &db, int32 version) { LOG(INFO) << "Init file database " << tag("version", version); @@ -49,11 +48,9 @@ Status init_file_db(SqliteDb &db, int32 version) { if (!has_table) { version = 0; - } else if (version < static_cast(DbVersion::DialogDbCreated)) { + } else if (version < static_cast(DbVersion::FixFileRemoteLocationKeyBug)) { TRY_STATUS(drop_file_db(db, version)); version = 0; - } else if (version < static_cast(DbVersion::FixFileRemoteLocationKeyBug)) { - TRY_STATUS(fix_file_remote_location_key_bug(db)); } if (version == 0) { @@ -306,30 +303,4 @@ std::shared_ptr create_file_db(std::shared_ptr(std::move(kv), scheduler_id); } -Status fix_file_remote_location_key_bug(SqliteDb &db) { - static const int32 OLD_KEY_MAGIC = 0x64378433; - SqliteKeyValue kv; - kv.init_with_connection(db.clone(), "files").ensure(); - auto ptr = StackAllocator::alloc(4); - MutableSlice prefix = ptr.as_slice(); - TlStorerUnsafe(prefix.ubegin()).store_int(OLD_KEY_MAGIC); - kv.get_by_prefix(prefix, [&](Slice key, Slice value) { - CHECK(TlParser(key).fetch_int() == OLD_KEY_MAGIC); - auto remote_str = PSTRING() << key.substr(4, 4) << Slice("\0\0\0\0") << key.substr(8); - FullRemoteFileLocation remote; - log_event::WithVersion parser(remote_str); - parser.set_version(static_cast(Version::Initial)); - parse(remote, parser); - parser.fetch_end(); - auto status = parser.get_status(); - if (status.is_ok()) { - kv.set(FileDbInterface::as_key(remote), value); - } - LOG(DEBUG) << "ERASE " << format::as_hex_dump<4>(Slice(key)); - kv.erase(key); - return true; - }); - return Status::OK(); -} - } // namespace td diff --git a/td/telegram/files/FileLocation.h b/td/telegram/files/FileLocation.h index 4bf0140a2..f78f7cb65 100644 --- a/td/telegram/files/FileLocation.h +++ b/td/telegram/files/FileLocation.h @@ -81,8 +81,6 @@ inline StringBuilder &operator<<(StringBuilder &sb, const PartialRemoteFileLocat struct PhotoRemoteFileLocation { int64 id_; int64 access_hash_; - int64 volume_id_; - int32 local_id_; PhotoSizeSource source_; template @@ -102,16 +100,19 @@ struct PhotoRemoteFileLocation { } bool operator<(const PhotoRemoteFileLocation &other) const { - return std::tie(id_, volume_id_, local_id_) < std::tie(other.id_, other.volume_id_, other.local_id_); + if (id_ != other.id_) { + return id_ < other.id_; + } + return source_.get_unique() < other.source_.get_unique(); } bool operator==(const PhotoRemoteFileLocation &other) const { - return std::tie(id_, volume_id_, local_id_) == std::tie(other.id_, other.volume_id_, other.local_id_); + return id_ == other.id_ && source_.get_unique() == other.source_.get_unique(); } }; inline StringBuilder &operator<<(StringBuilder &string_builder, const PhotoRemoteFileLocation &location) { - return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ - << ", volume_id = " << location.volume_id_ << ", local_id = " << location.local_id_ << "]"; + return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ << ", " + << location.source_ << "]"; } struct WebRemoteFileLocation { @@ -165,10 +166,10 @@ struct CommonRemoteFileLocation { } bool operator<(const CommonRemoteFileLocation &other) const { - return std::tie(id_) < std::tie(other.id_); + return id_ < other.id_; } bool operator==(const CommonRemoteFileLocation &other) const { - return std::tie(id_) == std::tie(other.id_); + return id_ == other.id_; } }; @@ -324,11 +325,11 @@ class FullRemoteFileLocation { return photo().source_; case LocationType::Common: case LocationType::Web: - return PhotoSizeSource(0); + return PhotoSizeSource(nullptr, 0, 0, 0); case LocationType::None: default: UNREACHABLE(); - return PhotoSizeSource(0); + return PhotoSizeSource(nullptr, 0, 0, 0); } } @@ -395,22 +396,24 @@ class FullRemoteFileLocation { tl_object_ptr as_input_file_location() const { switch (location_type()) { - case LocationType::Photo: - switch (photo().source_.get_type()) { + case LocationType::Photo: { + const auto &id = photo().id_; + const auto &access_hash = photo().access_hash_; + const auto &source = photo().source_; + switch (source.get_type()) { case PhotoSizeSource::Type::Legacy: - return make_tl_object( - photo().id_, photo().access_hash_, BufferSlice(file_reference_), photo().volume_id_, photo().local_id_, - photo().source_.legacy().secret); + UNREACHABLE(); + break; case PhotoSizeSource::Type::Thumbnail: { - auto &thumbnail = photo().source_.thumbnail(); + auto &thumbnail = source.thumbnail(); switch (thumbnail.file_type) { case FileType::Photo: return make_tl_object( - photo().id_, photo().access_hash_, BufferSlice(file_reference_), + id, access_hash, BufferSlice(file_reference_), std::string(1, static_cast(static_cast(thumbnail.thumbnail_type)))); case FileType::Thumbnail: return make_tl_object( - photo().id_, photo().access_hash_, BufferSlice(file_reference_), + id, access_hash, BufferSlice(file_reference_), std::string(1, static_cast(static_cast(thumbnail.thumbnail_type)))); default: UNREACHABLE(); @@ -420,22 +423,46 @@ class FullRemoteFileLocation { } case PhotoSizeSource::Type::DialogPhotoSmall: case PhotoSizeSource::Type::DialogPhotoBig: { - auto &dialog_photo = photo().source_.dialog_photo(); - bool is_big = photo().source_.get_type() == PhotoSizeSource::Type::DialogPhotoBig; + auto &dialog_photo = source.dialog_photo(); + bool is_big = source.get_type() == PhotoSizeSource::Type::DialogPhotoBig; return make_tl_object( - is_big * telegram_api::inputPeerPhotoFileLocation::Flags::BIG_MASK, false /*ignored*/, - dialog_photo.get_input_peer(), photo().volume_id_, photo().local_id_); + is_big * telegram_api::inputPeerPhotoFileLocation::BIG_MASK, false /*ignored*/, + dialog_photo.get_input_peer(), id); } - case PhotoSizeSource::Type::StickerSetThumbnail: { - auto &sticker_set_thumbnail = photo().source_.sticker_set_thumbnail(); + case PhotoSizeSource::Type::StickerSetThumbnail: + UNREACHABLE(); + break; + case PhotoSizeSource::Type::FullLegacy: { + const auto &full_legacy = source.full_legacy(); + return make_tl_object( + id, access_hash, BufferSlice(file_reference_), full_legacy.volume_id, full_legacy.local_id, + full_legacy.secret); + } + case PhotoSizeSource::Type::DialogPhotoSmallLegacy: + case PhotoSizeSource::Type::DialogPhotoBigLegacy: { + auto &dialog_photo = source.dialog_photo_legacy(); + bool is_big = source.get_type() == PhotoSizeSource::Type::DialogPhotoBigLegacy; + return make_tl_object( + is_big * telegram_api::inputPeerPhotoFileLocationLegacy::BIG_MASK, false /*ignored*/, + dialog_photo.get_input_peer(), dialog_photo.volume_id, dialog_photo.local_id); + } + case PhotoSizeSource::Type::StickerSetThumbnailLegacy: { + auto &sticker_set_thumbnail = source.sticker_set_thumbnail_legacy(); + return make_tl_object( + sticker_set_thumbnail.get_input_sticker_set(), sticker_set_thumbnail.volume_id, + sticker_set_thumbnail.local_id); + } + case PhotoSizeSource::Type::StickerSetThumbnailVersion: { + auto &sticker_set_thumbnail = source.sticker_set_thumbnail_version(); return make_tl_object(sticker_set_thumbnail.get_input_sticker_set(), - photo().volume_id_, photo().local_id_); + sticker_set_thumbnail.version); } default: break; } UNREACHABLE(); return nullptr; + } case LocationType::Common: if (is_encrypted_secret()) { return make_tl_object(common().id_, common().access_hash_); @@ -478,16 +505,16 @@ class FullRemoteFileLocation { return make_tl_object(common().id_, common().access_hash_); } - // TODO: this constructor is just for immediate unserialize + // this constructor is just for immediate unserialize FullRemoteFileLocation() = default; // photo - FullRemoteFileLocation(const PhotoSizeSource &source, int64 id, int64 access_hash, int32 local_id, int64 volume_id, - DcId dc_id, std::string file_reference) + FullRemoteFileLocation(const PhotoSizeSource &source, int64 id, int64 access_hash, DcId dc_id, + std::string file_reference) : file_type_(source.get_file_type()) , dc_id_(dc_id) , file_reference_(std::move(file_reference)) - , variant_(PhotoRemoteFileLocation{id, access_hash, volume_id, local_id, source}) { + , variant_(PhotoRemoteFileLocation{id, access_hash, source}) { CHECK(is_photo()); check_file_reference(); } diff --git a/td/telegram/files/FileLocation.hpp b/td/telegram/files/FileLocation.hpp index 0753bba9e..0c5c10cbf 100644 --- a/td/telegram/files/FileLocation.hpp +++ b/td/telegram/files/FileLocation.hpp @@ -44,9 +44,7 @@ void PhotoRemoteFileLocation::store(StorerT &storer) const { using td::store; store(id_, storer); store(access_hash_, storer); - store(volume_id_, storer); store(source_, storer); - store(local_id_, storer); } template @@ -54,25 +52,87 @@ void PhotoRemoteFileLocation::parse(ParserT &parser) { using td::parse; parse(id_, parser); parse(access_hash_, parser); - parse(volume_id_, parser); - if (parser.version() >= static_cast(Version::AddPhotoSizeSource)) { + if (parser.version() >= static_cast(Version::RemovePhotoVolumeAndLocalId)) { parse(source_, parser); } else { - int64 secret; - parse(secret, parser); - source_ = PhotoSizeSource(secret); + int64 volume_id; + PhotoSizeSource source; + int32 local_id; + parse(volume_id, parser); + if (parser.version() >= static_cast(Version::AddPhotoSizeSource)) { + parse(source, parser); + parse(local_id, parser); + } else { + int64 secret; + parse(secret, parser); + parse(local_id, parser); + source = PhotoSizeSource(nullptr, volume_id, local_id, secret); + } + + if (parser.get_error() != nullptr) { + return; + } + + switch (source.get_type()) { + case PhotoSizeSource::Type::Legacy: + source_ = PhotoSizeSource(nullptr, volume_id, local_id, source.legacy().secret); + break; + case PhotoSizeSource::Type::FullLegacy: + case PhotoSizeSource::Type::Thumbnail: + source_ = source; + break; + case PhotoSizeSource::Type::DialogPhotoSmall: + case PhotoSizeSource::Type::DialogPhotoBig: { + auto &dialog_photo = source.dialog_photo(); + bool is_big = source.get_type() == PhotoSizeSource::Type::DialogPhotoBig; + source_ = PhotoSizeSource(dialog_photo.dialog_id, dialog_photo.dialog_access_hash, is_big, volume_id, local_id); + break; + } + case PhotoSizeSource::Type::StickerSetThumbnail: { + auto &sticker_set_thumbnail = source.sticker_set_thumbnail(); + source_ = PhotoSizeSource(sticker_set_thumbnail.sticker_set_id, sticker_set_thumbnail.sticker_set_access_hash, + volume_id, local_id); + break; + } + default: + parser.set_error("Invalid PhotoSizeSource in legacy PhotoRemoteFileLocation"); + break; + } } - parse(local_id_, parser); } template void PhotoRemoteFileLocation::AsKey::store(StorerT &storer) const { using td::store; - if (!is_unique) { - store(key.id_, storer); + auto unique = key.source_.get_unique(); + switch (key.source_.get_type()) { + case PhotoSizeSource::Type::Legacy: + case PhotoSizeSource::Type::StickerSetThumbnail: + UNREACHABLE(); + break; + case PhotoSizeSource::Type::FullLegacy: + case PhotoSizeSource::Type::DialogPhotoSmallLegacy: + case PhotoSizeSource::Type::DialogPhotoBigLegacy: + case PhotoSizeSource::Type::StickerSetThumbnailLegacy: // 12/20 bytes + if (!is_unique) { + store(key.id_, storer); + } + storer.store_slice(unique); // volume_id + local_id + break; + case PhotoSizeSource::Type::DialogPhotoSmall: + case PhotoSizeSource::Type::DialogPhotoBig: + case PhotoSizeSource::Type::Thumbnail: // 8 + 1 bytes + store(key.id_, storer); // photo_id or document_id + storer.store_slice(unique); + break; + case PhotoSizeSource::Type::StickerSetThumbnailVersion: // 13 bytes + // sticker set thumbnails has no photo_id or document_id + storer.store_slice(unique); + break; + default: + UNREACHABLE(); + break; } - store(key.volume_id_, storer); - store(key.local_id_, storer); } template @@ -172,6 +232,7 @@ void FullRemoteFileLocation::parse(ParserT &parser) { } switch (photo().source_.get_type()) { case PhotoSizeSource::Type::Legacy: + case PhotoSizeSource::Type::FullLegacy: break; case PhotoSizeSource::Type::Thumbnail: if (photo().source_.get_file_type() != file_type_ || @@ -182,11 +243,15 @@ void FullRemoteFileLocation::parse(ParserT &parser) { break; case PhotoSizeSource::Type::DialogPhotoSmall: case PhotoSizeSource::Type::DialogPhotoBig: + case PhotoSizeSource::Type::DialogPhotoSmallLegacy: + case PhotoSizeSource::Type::DialogPhotoBigLegacy: if (file_type_ != FileType::ProfilePhoto) { parser.set_error("Invalid FileType in PhotoRemoteFileLocation DialogPhoto"); } break; case PhotoSizeSource::Type::StickerSetThumbnail: + case PhotoSizeSource::Type::StickerSetThumbnailLegacy: + case PhotoSizeSource::Type::StickerSetThumbnailVersion: if (file_type_ != FileType::Thumbnail) { parser.set_error("Invalid FileType in PhotoRemoteFileLocation StickerSetThumbnail"); } diff --git a/td/telegram/files/FileManager.h b/td/telegram/files/FileManager.h index 89ca92d73..d13bb5692 100644 --- a/td/telegram/files/FileManager.h +++ b/td/telegram/files/FileManager.h @@ -324,8 +324,7 @@ class FileView { return false; } auto type = remote_location().get_source().get_type(); - return type == PhotoSizeSource::Type::DialogPhotoBig || type == PhotoSizeSource::Type::DialogPhotoSmall || - type == PhotoSizeSource::Type::StickerSetThumbnail; + return type != PhotoSizeSource::Type::Legacy && type != PhotoSizeSource::Type::FullLegacy; } string get_persistent_file_id() const;