1 // 2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 #pragma once 8 9 #include "td/telegram/files/FileBitmask.h" 10 #include "td/telegram/files/FileType.h" 11 #include "td/telegram/net/DcId.h" 12 #include "td/telegram/PhotoSizeSource.h" 13 #include "td/telegram/telegram_api.h" 14 15 #include "td/utils/base64.h" 16 #include "td/utils/buffer.h" 17 #include "td/utils/common.h" 18 #include "td/utils/format.h" 19 #include "td/utils/logging.h" 20 #include "td/utils/Slice.h" 21 #include "td/utils/StringBuilder.h" 22 #include "td/utils/Variant.h" 23 24 #include <tuple> 25 #include <utility> 26 27 namespace td { 28 29 class FileReferenceView { 30 public: invalid_file_reference()31 static Slice invalid_file_reference() { 32 return Slice("#"); 33 } 34 }; 35 36 struct EmptyRemoteFileLocation { 37 template <class StorerT> storeEmptyRemoteFileLocation38 void store(StorerT &storer) const { 39 } 40 template <class ParserT> parseEmptyRemoteFileLocation41 void parse(ParserT &parser) { 42 } 43 }; 44 45 inline bool operator==(const EmptyRemoteFileLocation &lhs, const EmptyRemoteFileLocation &rhs) { 46 return true; 47 } 48 49 inline bool operator!=(const EmptyRemoteFileLocation &lhs, const EmptyRemoteFileLocation &rhs) { 50 return !(lhs == rhs); 51 } 52 53 struct PartialRemoteFileLocation { 54 int64 file_id_; 55 int32 part_count_; 56 int32 part_size_; 57 int32 ready_part_count_; 58 int32 is_big_; 59 60 template <class StorerT> 61 void store(StorerT &storer) const; 62 template <class ParserT> 63 void parse(ParserT &parser); 64 }; 65 66 inline bool operator==(const PartialRemoteFileLocation &lhs, const PartialRemoteFileLocation &rhs) { 67 return lhs.file_id_ == rhs.file_id_ && lhs.part_count_ == rhs.part_count_ && lhs.part_size_ == rhs.part_size_ && 68 lhs.ready_part_count_ == rhs.ready_part_count_ && lhs.is_big_ == rhs.is_big_; 69 } 70 71 inline bool operator!=(const PartialRemoteFileLocation &lhs, const PartialRemoteFileLocation &rhs) { 72 return !(lhs == rhs); 73 } 74 75 inline StringBuilder &operator<<(StringBuilder &sb, const PartialRemoteFileLocation &location) { 76 return sb << '[' << (location.is_big_ ? "Big" : "Small") << " partial remote location with " << location.part_count_ 77 << " parts of size " << location.part_size_ << " with " << location.ready_part_count_ << " ready parts]"; 78 } 79 80 struct PhotoRemoteFileLocation { 81 int64 id_; 82 int64 access_hash_; 83 PhotoSizeSource source_; 84 85 template <class StorerT> 86 void store(StorerT &storer) const; 87 template <class ParserT> 88 void parse(ParserT &parser); 89 90 struct AsKey { 91 const PhotoRemoteFileLocation &key; 92 bool is_unique; 93 94 template <class StorerT> 95 void store(StorerT &storer) const; 96 }; as_keyPhotoRemoteFileLocation97 AsKey as_key(bool is_unique) const { 98 return AsKey{*this, is_unique}; 99 } 100 101 bool operator<(const PhotoRemoteFileLocation &other) const { 102 if (id_ != other.id_) { 103 return id_ < other.id_; 104 } 105 return source_.get_unique() < other.source_.get_unique(); 106 } 107 bool operator==(const PhotoRemoteFileLocation &other) const { 108 return id_ == other.id_ && source_.get_unique() == other.source_.get_unique(); 109 } 110 }; 111 112 inline StringBuilder &operator<<(StringBuilder &string_builder, const PhotoRemoteFileLocation &location) { 113 return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ << ", " 114 << location.source_ << "]"; 115 } 116 117 struct WebRemoteFileLocation { 118 string url_; 119 int64 access_hash_; 120 121 template <class StorerT> 122 void store(StorerT &storer) const; 123 template <class ParserT> 124 void parse(ParserT &parser); 125 126 struct AsKey { 127 const WebRemoteFileLocation &key; 128 129 template <class StorerT> 130 void store(StorerT &storer) const; 131 }; as_keyWebRemoteFileLocation132 AsKey as_key(bool /*is_unique*/) const { 133 return AsKey{*this}; 134 } 135 136 bool operator<(const WebRemoteFileLocation &other) const { 137 return url_ < other.url_; 138 } 139 bool operator==(const WebRemoteFileLocation &other) const { 140 return url_ == other.url_; 141 } 142 }; 143 144 inline StringBuilder &operator<<(StringBuilder &string_builder, const WebRemoteFileLocation &location) { 145 return string_builder << "[url = " << location.url_ << ", access_hash = " << location.access_hash_ << "]"; 146 } 147 148 struct CommonRemoteFileLocation { 149 int64 id_; 150 int64 access_hash_; 151 152 template <class StorerT> 153 void store(StorerT &storer) const; 154 template <class ParserT> 155 void parse(ParserT &parser); 156 157 struct AsKey { 158 const CommonRemoteFileLocation &key; 159 160 template <class StorerT> 161 void store(StorerT &storer) const; 162 }; as_keyCommonRemoteFileLocation163 AsKey as_key(bool /*is_unique*/) const { 164 return AsKey{*this}; 165 } 166 167 bool operator<(const CommonRemoteFileLocation &other) const { 168 return id_ < other.id_; 169 } 170 bool operator==(const CommonRemoteFileLocation &other) const { 171 return id_ == other.id_; 172 } 173 }; 174 175 inline StringBuilder &operator<<(StringBuilder &string_builder, const CommonRemoteFileLocation &location) { 176 return string_builder << "[ID = " << location.id_ << ", access_hash = " << location.access_hash_ << "]"; 177 } 178 179 class FullRemoteFileLocation { 180 public: 181 FileType file_type_{FileType::None}; 182 183 private: 184 static constexpr int32 WEB_LOCATION_FLAG = 1 << 24; 185 static constexpr int32 FILE_REFERENCE_FLAG = 1 << 25; 186 DcId dc_id_; 187 string file_reference_; 188 enum class LocationType : int32 { Web, Photo, Common, None }; 189 Variant<WebRemoteFileLocation, PhotoRemoteFileLocation, CommonRemoteFileLocation> variant_; 190 location_type()191 LocationType location_type() const { 192 if (is_web()) { 193 return LocationType::Web; 194 } 195 switch (file_type_) { 196 case FileType::Photo: 197 case FileType::ProfilePhoto: 198 case FileType::Thumbnail: 199 case FileType::EncryptedThumbnail: 200 case FileType::Wallpaper: 201 return LocationType::Photo; 202 case FileType::Video: 203 case FileType::VoiceNote: 204 case FileType::Document: 205 case FileType::Sticker: 206 case FileType::Audio: 207 case FileType::Animation: 208 case FileType::Encrypted: 209 case FileType::VideoNote: 210 case FileType::SecureRaw: 211 case FileType::Secure: 212 case FileType::Background: 213 case FileType::DocumentAsFile: 214 return LocationType::Common; 215 case FileType::None: 216 case FileType::Size: 217 default: 218 UNREACHABLE(); 219 case FileType::Temp: 220 return LocationType::None; 221 } 222 } 223 web()224 WebRemoteFileLocation &web() { 225 return variant_.get<WebRemoteFileLocation>(); 226 } photo()227 PhotoRemoteFileLocation &photo() { 228 return variant_.get<PhotoRemoteFileLocation>(); 229 } common()230 CommonRemoteFileLocation &common() { 231 return variant_.get<CommonRemoteFileLocation>(); 232 } web()233 const WebRemoteFileLocation &web() const { 234 return variant_.get<WebRemoteFileLocation>(); 235 } photo()236 const PhotoRemoteFileLocation &photo() const { 237 return variant_.get<PhotoRemoteFileLocation>(); 238 } common()239 const CommonRemoteFileLocation &common() const { 240 return variant_.get<CommonRemoteFileLocation>(); 241 } 242 243 friend StringBuilder &operator<<(StringBuilder &string_builder, 244 const FullRemoteFileLocation &full_remote_file_location); 245 key_type()246 int32 key_type() const { 247 auto type = static_cast<int32>(file_type_); 248 if (is_web()) { 249 type |= WEB_LOCATION_FLAG; 250 } 251 return type; 252 } 253 check_file_reference()254 void check_file_reference() { 255 if (file_reference_ == FileReferenceView::invalid_file_reference()) { 256 LOG(ERROR) << "Tried to register file with invalid file reference"; 257 file_reference_.clear(); 258 } 259 } 260 261 public: 262 template <class StorerT> 263 void store(StorerT &storer) const; 264 template <class ParserT> 265 void parse(ParserT &parser); 266 267 struct AsKey { 268 const FullRemoteFileLocation &key; 269 270 template <class StorerT> 271 void store(StorerT &storer) const; 272 }; as_key()273 AsKey as_key() const { 274 return AsKey{*this}; 275 } 276 277 struct AsUnique { 278 const FullRemoteFileLocation &key; 279 280 template <class StorerT> 281 void store(StorerT &storer) const; 282 }; as_unique()283 AsUnique as_unique() const { 284 return AsUnique{*this}; 285 } 286 get_dc_id()287 DcId get_dc_id() const { 288 CHECK(!is_web()); 289 return dc_id_; 290 } 291 get_access_hash()292 int64 get_access_hash() const { 293 switch (location_type()) { 294 case LocationType::Photo: 295 return photo().access_hash_; 296 case LocationType::Common: 297 return common().access_hash_; 298 case LocationType::Web: 299 return web().access_hash_; 300 case LocationType::None: 301 default: 302 UNREACHABLE(); 303 return 0; 304 } 305 } 306 get_id()307 int64 get_id() const { 308 switch (location_type()) { 309 case LocationType::Photo: 310 return photo().id_; 311 case LocationType::Common: 312 return common().id_; 313 case LocationType::Web: 314 case LocationType::None: 315 default: 316 UNREACHABLE(); 317 return 0; 318 } 319 } 320 get_source()321 PhotoSizeSource get_source() const { 322 switch (location_type()) { 323 case LocationType::Photo: 324 return photo().source_; 325 case LocationType::Common: 326 case LocationType::Web: 327 return PhotoSizeSource::full_legacy(0, 0, 0); 328 case LocationType::None: 329 default: 330 UNREACHABLE(); 331 return PhotoSizeSource::full_legacy(0, 0, 0); 332 } 333 } 334 set_source(PhotoSizeSource source)335 void set_source(PhotoSizeSource source) { 336 CHECK(is_photo()); 337 file_type_ = source.get_file_type("set_source"); 338 photo().source_ = std::move(source); 339 } 340 delete_file_reference(Slice bad_file_reference)341 bool delete_file_reference(Slice bad_file_reference) { 342 if (file_reference_ != FileReferenceView::invalid_file_reference() && file_reference_ == bad_file_reference) { 343 file_reference_ = FileReferenceView::invalid_file_reference().str(); 344 return true; 345 } 346 return false; 347 } 348 has_file_reference()349 bool has_file_reference() const { 350 return file_reference_ != FileReferenceView::invalid_file_reference(); 351 } 352 get_file_reference()353 Slice get_file_reference() const { 354 return file_reference_; 355 } 356 get_url()357 string get_url() const { 358 if (is_web()) { 359 return web().url_; 360 } 361 362 return string(); 363 } 364 is_web()365 bool is_web() const { 366 return variant_.get_offset() == 0; 367 } is_photo()368 bool is_photo() const { 369 return location_type() == LocationType::Photo; 370 } is_common()371 bool is_common() const { 372 return location_type() == LocationType::Common; 373 } is_encrypted_secret()374 bool is_encrypted_secret() const { 375 return file_type_ == FileType::Encrypted; 376 } is_encrypted_secure()377 bool is_encrypted_secure() const { 378 return file_type_ == FileType::Secure; 379 } is_encrypted_any()380 bool is_encrypted_any() const { 381 return is_encrypted_secret() || is_encrypted_secure(); 382 } is_secure()383 bool is_secure() const { 384 return file_type_ == FileType::SecureRaw || file_type_ == FileType::Secure; 385 } is_document()386 bool is_document() const { 387 return is_common() && !is_secure() && !is_encrypted_secret(); 388 } 389 390 #define as_input_web_file_location() as_input_web_file_location_impl(__FILE__, __LINE__) as_input_web_file_location_impl(const char * file,int line)391 tl_object_ptr<telegram_api::inputWebFileLocation> as_input_web_file_location_impl(const char *file, int line) const { 392 LOG_CHECK(is_web()) << file << ' ' << line; 393 return make_tl_object<telegram_api::inputWebFileLocation>(web().url_, web().access_hash_); 394 } 395 as_input_file_location()396 tl_object_ptr<telegram_api::InputFileLocation> as_input_file_location() const { 397 switch (location_type()) { 398 case LocationType::Photo: { 399 const auto &id = photo().id_; 400 const auto &access_hash = photo().access_hash_; 401 const auto &source = photo().source_; 402 switch (source.get_type("as_input_file_location")) { 403 case PhotoSizeSource::Type::Legacy: 404 UNREACHABLE(); 405 break; 406 case PhotoSizeSource::Type::Thumbnail: { 407 auto &thumbnail = source.thumbnail(); 408 switch (thumbnail.file_type) { 409 case FileType::Photo: 410 return make_tl_object<telegram_api::inputPhotoFileLocation>( 411 id, access_hash, BufferSlice(file_reference_), 412 std::string(1, static_cast<char>(static_cast<uint8>(thumbnail.thumbnail_type)))); 413 case FileType::Thumbnail: 414 return make_tl_object<telegram_api::inputDocumentFileLocation>( 415 id, access_hash, BufferSlice(file_reference_), 416 std::string(1, static_cast<char>(static_cast<uint8>(thumbnail.thumbnail_type)))); 417 default: 418 UNREACHABLE(); 419 break; 420 } 421 break; 422 } 423 case PhotoSizeSource::Type::DialogPhotoSmall: 424 case PhotoSizeSource::Type::DialogPhotoBig: { 425 auto &dialog_photo = source.dialog_photo(); 426 bool is_big = source.get_type("as_input_file_location 2") == PhotoSizeSource::Type::DialogPhotoBig; 427 return make_tl_object<telegram_api::inputPeerPhotoFileLocation>( 428 is_big * telegram_api::inputPeerPhotoFileLocation::BIG_MASK, false /*ignored*/, 429 dialog_photo.get_input_peer(), id); 430 } 431 case PhotoSizeSource::Type::StickerSetThumbnail: 432 UNREACHABLE(); 433 break; 434 case PhotoSizeSource::Type::FullLegacy: { 435 const auto &full_legacy = source.full_legacy(); 436 return make_tl_object<telegram_api::inputPhotoLegacyFileLocation>( 437 id, access_hash, BufferSlice(file_reference_), full_legacy.volume_id, full_legacy.local_id, 438 full_legacy.secret); 439 } 440 case PhotoSizeSource::Type::DialogPhotoSmallLegacy: 441 case PhotoSizeSource::Type::DialogPhotoBigLegacy: { 442 auto &dialog_photo = source.dialog_photo_legacy(); 443 bool is_big = source.get_type("as_input_file_location 3") == PhotoSizeSource::Type::DialogPhotoBigLegacy; 444 return make_tl_object<telegram_api::inputPeerPhotoFileLocationLegacy>( 445 is_big * telegram_api::inputPeerPhotoFileLocationLegacy::BIG_MASK, false /*ignored*/, 446 dialog_photo.get_input_peer(), dialog_photo.volume_id, dialog_photo.local_id); 447 } 448 case PhotoSizeSource::Type::StickerSetThumbnailLegacy: { 449 auto &sticker_set_thumbnail = source.sticker_set_thumbnail_legacy(); 450 return make_tl_object<telegram_api::inputStickerSetThumbLegacy>( 451 sticker_set_thumbnail.get_input_sticker_set(), sticker_set_thumbnail.volume_id, 452 sticker_set_thumbnail.local_id); 453 } 454 case PhotoSizeSource::Type::StickerSetThumbnailVersion: { 455 auto &sticker_set_thumbnail = source.sticker_set_thumbnail_version(); 456 return make_tl_object<telegram_api::inputStickerSetThumb>(sticker_set_thumbnail.get_input_sticker_set(), 457 sticker_set_thumbnail.version); 458 } 459 default: 460 break; 461 } 462 UNREACHABLE(); 463 return nullptr; 464 } 465 case LocationType::Common: 466 if (is_encrypted_secret()) { 467 return make_tl_object<telegram_api::inputEncryptedFileLocation>(common().id_, common().access_hash_); 468 } else if (is_secure()) { 469 return make_tl_object<telegram_api::inputSecureFileLocation>(common().id_, common().access_hash_); 470 } else { 471 return make_tl_object<telegram_api::inputDocumentFileLocation>(common().id_, common().access_hash_, 472 BufferSlice(file_reference_), string()); 473 } 474 case LocationType::Web: 475 case LocationType::None: 476 default: 477 UNREACHABLE(); 478 return nullptr; 479 } 480 } 481 482 #define as_input_document() as_input_document_impl(__FILE__, __LINE__) as_input_document_impl(const char * file,int line)483 tl_object_ptr<telegram_api::inputDocument> as_input_document_impl(const char *file, int line) const { 484 LOG_CHECK(is_common()) << file << ' ' << line; 485 LOG_CHECK(is_document()) << file << ' ' << line; 486 return make_tl_object<telegram_api::inputDocument>(common().id_, common().access_hash_, 487 BufferSlice(file_reference_)); 488 } 489 490 #define as_input_photo() as_input_photo_impl(__FILE__, __LINE__) as_input_photo_impl(const char * file,int line)491 tl_object_ptr<telegram_api::inputPhoto> as_input_photo_impl(const char *file, int line) const { 492 LOG_CHECK(is_photo()) << file << ' ' << line; 493 return make_tl_object<telegram_api::inputPhoto>(photo().id_, photo().access_hash_, BufferSlice(file_reference_)); 494 } 495 as_input_encrypted_file()496 tl_object_ptr<telegram_api::inputEncryptedFile> as_input_encrypted_file() const { 497 CHECK(is_encrypted_secret()); 498 return make_tl_object<telegram_api::inputEncryptedFile>(common().id_, common().access_hash_); 499 } 500 501 #define as_input_secure_file() as_input_secure_file_impl(__FILE__, __LINE__) as_input_secure_file_impl(const char * file,int line)502 tl_object_ptr<telegram_api::inputSecureFile> as_input_secure_file_impl(const char *file, int line) const { 503 LOG_CHECK(is_secure()) << file << ' ' << line; 504 return make_tl_object<telegram_api::inputSecureFile>(common().id_, common().access_hash_); 505 } 506 507 // this constructor is just for immediate unserialize 508 FullRemoteFileLocation() = default; 509 510 // photo FullRemoteFileLocation(const PhotoSizeSource & source,int64 id,int64 access_hash,DcId dc_id,std::string file_reference)511 FullRemoteFileLocation(const PhotoSizeSource &source, int64 id, int64 access_hash, DcId dc_id, 512 std::string file_reference) 513 : file_type_(source.get_file_type("FullRemoteFileLocation")) 514 , dc_id_(dc_id) 515 , file_reference_(std::move(file_reference)) 516 , variant_(PhotoRemoteFileLocation{id, access_hash, source}) { 517 CHECK(is_photo()); 518 check_file_reference(); 519 } 520 521 // document FullRemoteFileLocation(FileType file_type,int64 id,int64 access_hash,DcId dc_id,std::string file_reference)522 FullRemoteFileLocation(FileType file_type, int64 id, int64 access_hash, DcId dc_id, std::string file_reference) 523 : file_type_(file_type) 524 , dc_id_(dc_id) 525 , file_reference_(std::move(file_reference)) 526 , variant_(CommonRemoteFileLocation{id, access_hash}) { 527 CHECK(is_common()); 528 check_file_reference(); 529 } 530 531 // web document FullRemoteFileLocation(FileType file_type,string url,int64 access_hash)532 FullRemoteFileLocation(FileType file_type, string url, int64 access_hash) 533 : file_type_(file_type), dc_id_(), variant_(WebRemoteFileLocation{std::move(url), access_hash}) { 534 CHECK(is_web()); 535 CHECK(!web().url_.empty()); 536 } 537 538 bool operator<(const FullRemoteFileLocation &other) const { 539 if (key_type() != other.key_type()) { 540 return key_type() < other.key_type(); 541 } 542 if (dc_id_ != other.dc_id_) { 543 return dc_id_ < other.dc_id_; 544 } 545 switch (location_type()) { 546 case LocationType::Photo: 547 return photo() < other.photo(); 548 case LocationType::Common: 549 return common() < other.common(); 550 case LocationType::Web: 551 return web() < other.web(); 552 case LocationType::None: 553 default: 554 UNREACHABLE(); 555 return false; 556 } 557 } 558 bool operator==(const FullRemoteFileLocation &other) const { 559 if (key_type() != other.key_type()) { 560 return false; 561 } 562 if (dc_id_ != other.dc_id_) { 563 return false; 564 } 565 switch (location_type()) { 566 case LocationType::Photo: 567 return photo() == other.photo(); 568 case LocationType::Common: 569 return common() == other.common(); 570 case LocationType::Web: 571 return web() == other.web(); 572 case LocationType::None: 573 default: 574 UNREACHABLE(); 575 return false; 576 } 577 } 578 579 static const int32 KEY_MAGIC = 0x64374632; 580 }; 581 582 inline StringBuilder &operator<<(StringBuilder &string_builder, 583 const FullRemoteFileLocation &full_remote_file_location) { 584 string_builder << "[" << full_remote_file_location.file_type_; 585 if (!full_remote_file_location.is_web()) { 586 string_builder << ", " << full_remote_file_location.get_dc_id(); 587 } 588 if (!full_remote_file_location.file_reference_.empty()) { 589 string_builder << ", " << tag("file_reference", base64_encode(full_remote_file_location.file_reference_)); 590 } 591 592 string_builder << ", location = "; 593 if (full_remote_file_location.is_web()) { 594 string_builder << full_remote_file_location.web(); 595 } else if (full_remote_file_location.is_photo()) { 596 string_builder << full_remote_file_location.photo(); 597 } else if (full_remote_file_location.is_common()) { 598 string_builder << full_remote_file_location.common(); 599 } 600 601 return string_builder << "]"; 602 } 603 604 class RemoteFileLocation { 605 public: 606 enum class Type : int32 { Empty, Partial, Full }; 607 type()608 Type type() const { 609 return static_cast<Type>(variant_.get_offset()); 610 } 611 partial()612 PartialRemoteFileLocation &partial() { 613 return variant_.get<1>(); 614 } full()615 FullRemoteFileLocation &full() { 616 return variant_.get<2>(); 617 } partial()618 const PartialRemoteFileLocation &partial() const { 619 return variant_.get<1>(); 620 } full()621 const FullRemoteFileLocation &full() const { 622 return variant_.get<2>(); 623 } 624 625 template <class StorerT> 626 void store(StorerT &storer) const; 627 template <class ParserT> 628 void parse(ParserT &parser); 629 RemoteFileLocation()630 RemoteFileLocation() : variant_{EmptyRemoteFileLocation{}} { 631 } RemoteFileLocation(FullRemoteFileLocation full)632 explicit RemoteFileLocation(FullRemoteFileLocation full) : variant_(std::move(full)) { 633 } RemoteFileLocation(PartialRemoteFileLocation partial)634 explicit RemoteFileLocation(PartialRemoteFileLocation partial) : variant_(std::move(partial)) { 635 } 636 637 private: 638 Variant<EmptyRemoteFileLocation, PartialRemoteFileLocation, FullRemoteFileLocation> variant_; 639 640 friend bool operator==(const RemoteFileLocation &lhs, const RemoteFileLocation &rhs); 641 is_empty()642 bool is_empty() const { 643 switch (type()) { 644 case Type::Empty: 645 return true; 646 case Type::Partial: 647 return partial().ready_part_count_ == 0; 648 case Type::Full: 649 return false; 650 default: 651 UNREACHABLE(); 652 return false; 653 } 654 } 655 }; 656 657 inline bool operator==(const RemoteFileLocation &lhs, const RemoteFileLocation &rhs) { 658 if (lhs.is_empty() && rhs.is_empty()) { 659 return true; 660 } 661 return lhs.variant_ == rhs.variant_; 662 } 663 664 inline bool operator!=(const RemoteFileLocation &lhs, const RemoteFileLocation &rhs) { 665 return !(lhs == rhs); 666 } 667 668 inline StringBuilder &operator<<(StringBuilder &sb, const RemoteFileLocation &location) { 669 switch (location.type()) { 670 case RemoteFileLocation::Type::Empty: 671 return sb << "[empty remote location]"; 672 case RemoteFileLocation::Type::Partial: 673 return sb << location.partial(); 674 case RemoteFileLocation::Type::Full: 675 return sb << location.full(); 676 default: 677 UNREACHABLE(); 678 return sb; 679 } 680 } 681 682 struct EmptyLocalFileLocation { 683 template <class StorerT> storeEmptyLocalFileLocation684 void store(StorerT &storer) const { 685 } 686 template <class ParserT> parseEmptyLocalFileLocation687 void parse(ParserT &parser) { 688 } 689 }; 690 691 inline bool operator==(const EmptyLocalFileLocation &lhs, const EmptyLocalFileLocation &rhs) { 692 return true; 693 } 694 695 inline bool operator!=(const EmptyLocalFileLocation &lhs, const EmptyLocalFileLocation &rhs) { 696 return !(lhs == rhs); 697 } 698 699 struct PartialLocalFileLocation { 700 FileType file_type_; 701 int32 part_size_; 702 string path_; 703 string iv_; 704 string ready_bitmask_; 705 706 template <class StorerT> 707 void store(StorerT &storer) const; 708 template <class ParserT> 709 void parse(ParserT &parser); 710 }; 711 712 inline bool operator==(const PartialLocalFileLocation &lhs, const PartialLocalFileLocation &rhs) { 713 return lhs.file_type_ == rhs.file_type_ && lhs.path_ == rhs.path_ && lhs.part_size_ == rhs.part_size_ && 714 lhs.iv_ == rhs.iv_ && lhs.ready_bitmask_ == rhs.ready_bitmask_; 715 } 716 717 inline bool operator!=(const PartialLocalFileLocation &lhs, const PartialLocalFileLocation &rhs) { 718 return !(lhs == rhs); 719 } 720 721 inline StringBuilder &operator<<(StringBuilder &sb, const PartialLocalFileLocation &location) { 722 return sb << "[partial local location of " << location.file_type_ << " with part size " << location.part_size_ 723 << " and ready parts " << Bitmask(Bitmask::Decode{}, location.ready_bitmask_) << "] at \"" << location.path_ 724 << '"'; 725 } 726 727 struct FullLocalFileLocation { 728 FileType file_type_; 729 string path_; 730 uint64 mtime_nsec_; 731 732 template <class StorerT> 733 void store(StorerT &storer) const; 734 template <class ParserT> 735 void parse(ParserT &parser); 736 as_keyFullLocalFileLocation737 const FullLocalFileLocation &as_key() const { 738 return *this; 739 } 740 741 // TODO: remove this constructor FullLocalFileLocationFullLocalFileLocation742 FullLocalFileLocation() : file_type_(FileType::Photo) { 743 } FullLocalFileLocationFullLocalFileLocation744 FullLocalFileLocation(FileType file_type, string path, uint64 mtime_nsec) 745 : file_type_(file_type), path_(std::move(path)), mtime_nsec_(mtime_nsec) { 746 } 747 748 static const int32 KEY_MAGIC = 0x84373817; 749 }; 750 751 inline bool operator<(const FullLocalFileLocation &lhs, const FullLocalFileLocation &rhs) { 752 return std::tie(lhs.file_type_, lhs.mtime_nsec_, lhs.path_) < std::tie(rhs.file_type_, rhs.mtime_nsec_, rhs.path_); 753 } 754 755 inline bool operator==(const FullLocalFileLocation &lhs, const FullLocalFileLocation &rhs) { 756 return std::tie(lhs.file_type_, lhs.mtime_nsec_, lhs.path_) == std::tie(rhs.file_type_, rhs.mtime_nsec_, rhs.path_); 757 } 758 759 inline bool operator!=(const FullLocalFileLocation &lhs, const FullLocalFileLocation &rhs) { 760 return !(lhs == rhs); 761 } 762 763 inline StringBuilder &operator<<(StringBuilder &sb, const FullLocalFileLocation &location) { 764 return sb << "[full local location of " << location.file_type_ << "] at \"" << location.path_ << '"'; 765 } 766 767 struct PartialLocalFileLocationPtr { 768 unique_ptr<PartialLocalFileLocation> location_; // must never be equal to nullptr 769 PartialLocalFileLocationPtrPartialLocalFileLocationPtr770 PartialLocalFileLocationPtr() : location_(make_unique<PartialLocalFileLocation>()) { 771 } PartialLocalFileLocationPtrPartialLocalFileLocationPtr772 explicit PartialLocalFileLocationPtr(PartialLocalFileLocation location) 773 : location_(make_unique<PartialLocalFileLocation>(std::move(location))) { 774 } PartialLocalFileLocationPtrPartialLocalFileLocationPtr775 PartialLocalFileLocationPtr(const PartialLocalFileLocationPtr &other) 776 : location_(make_unique<PartialLocalFileLocation>(*other.location_)) { 777 } 778 PartialLocalFileLocationPtr &operator=(const PartialLocalFileLocationPtr &other) { 779 if (this != &other) { 780 *location_ = *other.location_; 781 } 782 return *this; 783 } PartialLocalFileLocationPtrPartialLocalFileLocationPtr784 PartialLocalFileLocationPtr(PartialLocalFileLocationPtr &&other) noexcept 785 : location_(make_unique<PartialLocalFileLocation>(std::move(*other.location_))) { 786 } 787 PartialLocalFileLocationPtr &operator=(PartialLocalFileLocationPtr &&other) noexcept { 788 *location_ = std::move(*other.location_); 789 return *this; 790 } 791 ~PartialLocalFileLocationPtr() = default; 792 793 template <class StorerT> 794 void store(StorerT &storer) const; 795 template <class ParserT> 796 void parse(ParserT &parser); 797 }; 798 799 inline bool operator==(const PartialLocalFileLocationPtr &lhs, const PartialLocalFileLocationPtr &rhs) { 800 return *lhs.location_ == *rhs.location_; 801 } 802 803 class LocalFileLocation { 804 public: 805 enum class Type : int32 { Empty, Partial, Full }; 806 type()807 Type type() const { 808 return static_cast<Type>(variant_.get_offset()); 809 } 810 partial()811 PartialLocalFileLocation &partial() { 812 return *variant_.get<1>().location_; 813 } full()814 FullLocalFileLocation &full() { 815 return variant_.get<2>(); 816 } partial()817 const PartialLocalFileLocation &partial() const { 818 return *variant_.get<1>().location_; 819 } full()820 const FullLocalFileLocation &full() const { 821 return variant_.get<2>(); 822 } 823 file_name()824 CSlice file_name() const { 825 switch (type()) { 826 case Type::Partial: 827 return partial().path_; 828 case Type::Full: 829 return full().path_; 830 case Type::Empty: 831 default: 832 return CSlice(); 833 } 834 } 835 836 template <class StorerT> 837 void store(StorerT &storer) const; 838 template <class ParserT> 839 void parse(ParserT &parser); 840 LocalFileLocation()841 LocalFileLocation() : variant_{EmptyLocalFileLocation()} { 842 } LocalFileLocation(PartialLocalFileLocation partial)843 explicit LocalFileLocation(PartialLocalFileLocation partial) 844 : variant_(PartialLocalFileLocationPtr(std::move(partial))) { 845 } LocalFileLocation(FullLocalFileLocation full)846 explicit LocalFileLocation(FullLocalFileLocation full) : variant_(std::move(full)) { 847 } LocalFileLocation(FileType file_type,string path,uint64 mtime_nsec)848 LocalFileLocation(FileType file_type, string path, uint64 mtime_nsec) 849 : variant_(FullLocalFileLocation{file_type, std::move(path), mtime_nsec}) { 850 } 851 852 private: 853 Variant<EmptyLocalFileLocation, PartialLocalFileLocationPtr, FullLocalFileLocation> variant_; 854 855 friend bool operator==(const LocalFileLocation &lhs, const LocalFileLocation &rhs); 856 }; 857 858 inline bool operator==(const LocalFileLocation &lhs, const LocalFileLocation &rhs) { 859 return lhs.variant_ == rhs.variant_; 860 } 861 862 inline bool operator!=(const LocalFileLocation &lhs, const LocalFileLocation &rhs) { 863 return !(lhs == rhs); 864 } 865 866 inline StringBuilder &operator<<(StringBuilder &sb, const LocalFileLocation &location) { 867 switch (location.type()) { 868 case LocalFileLocation::Type::Empty: 869 return sb << "[empty local location]"; 870 case LocalFileLocation::Type::Partial: 871 return sb << location.partial(); 872 case LocalFileLocation::Type::Full: 873 return sb << location.full(); 874 default: 875 UNREACHABLE(); 876 return sb; 877 } 878 } 879 880 struct FullGenerateFileLocation { 881 FileType file_type_{FileType::None}; 882 string original_path_; 883 string conversion_; 884 static const int32 KEY_MAGIC = 0x8b60a1c8; 885 886 template <class StorerT> 887 void store(StorerT &storer) const; 888 template <class ParserT> 889 void parse(ParserT &parser); 890 as_keyFullGenerateFileLocation891 const FullGenerateFileLocation &as_key() const { 892 return *this; 893 } 894 FullGenerateFileLocation() = default; FullGenerateFileLocationFullGenerateFileLocation895 FullGenerateFileLocation(FileType file_type, string original_path, string conversion) 896 : file_type_(file_type), original_path_(std::move(original_path)), conversion_(std::move(conversion)) { 897 } 898 }; 899 900 inline bool operator<(const FullGenerateFileLocation &lhs, const FullGenerateFileLocation &rhs) { 901 return std::tie(lhs.file_type_, lhs.original_path_, lhs.conversion_) < 902 std::tie(rhs.file_type_, rhs.original_path_, rhs.conversion_); 903 } 904 905 inline bool operator==(const FullGenerateFileLocation &lhs, const FullGenerateFileLocation &rhs) { 906 return std::tie(lhs.file_type_, lhs.original_path_, lhs.conversion_) == 907 std::tie(rhs.file_type_, rhs.original_path_, rhs.conversion_); 908 } 909 910 inline bool operator!=(const FullGenerateFileLocation &lhs, const FullGenerateFileLocation &rhs) { 911 return !(lhs == rhs); 912 } 913 914 inline StringBuilder &operator<<(StringBuilder &string_builder, 915 const FullGenerateFileLocation &full_generated_file_location) { 916 return string_builder << '[' << tag("file_type", full_generated_file_location.file_type_) 917 << tag("original_path", full_generated_file_location.original_path_) 918 << tag("conversion", full_generated_file_location.conversion_) << ']'; 919 } 920 921 class GenerateFileLocation { 922 public: 923 enum class Type : int32 { Empty, Full }; 924 type()925 Type type() const { 926 return type_; 927 } 928 full()929 FullGenerateFileLocation &full() { 930 CHECK(type_ == Type::Full); 931 return full_; 932 } full()933 const FullGenerateFileLocation &full() const { 934 CHECK(type_ == Type::Full); 935 return full_; 936 } 937 938 template <class StorerT> 939 void store(StorerT &storer) const; 940 template <class ParserT> 941 void parse(ParserT &parser); 942 GenerateFileLocation()943 GenerateFileLocation() : type_(Type::Empty) { 944 } 945 GenerateFileLocation(const FullGenerateFileLocation & full)946 explicit GenerateFileLocation(const FullGenerateFileLocation &full) : type_(Type::Full), full_(full) { 947 } 948 GenerateFileLocation(FileType file_type,string original_path,string conversion)949 GenerateFileLocation(FileType file_type, string original_path, string conversion) 950 : type_(Type::Full), full_{file_type, std::move(original_path), std::move(conversion)} { 951 } 952 953 private: 954 Type type_; 955 FullGenerateFileLocation full_; 956 }; 957 958 inline bool operator==(const GenerateFileLocation &lhs, const GenerateFileLocation &rhs) { 959 if (lhs.type() != rhs.type()) { 960 return false; 961 } 962 switch (lhs.type()) { 963 case GenerateFileLocation::Type::Empty: 964 return true; 965 case GenerateFileLocation::Type::Full: 966 return lhs.full() == rhs.full(); 967 } 968 UNREACHABLE(); 969 return false; 970 } 971 972 inline bool operator!=(const GenerateFileLocation &lhs, const GenerateFileLocation &rhs) { 973 return !(lhs == rhs); 974 } 975 976 } // namespace td 977