/* 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 */ #pragma once #include "base/flags.h" #include "base/binary_guard.h" #include "data/data_types.h" #include "ui/image/image.h" class mtpFileLoader; namespace Images { class Source; } // namespace Images namespace Storage { namespace Cache { struct Key; } // namespace Cache } // namespace Storage namespace Media { namespace Streaming { class Loader; } // namespace Streaming } // namespace Media namespace Data { class Session; } // namespace Data namespace Main { class Session; } // namespace Main inline uint64 mediaMix32To64(int32 a, int32 b) { return (uint64(*reinterpret_cast(&a)) << 32) | uint64(*reinterpret_cast(&b)); } // version field removed from document. inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) { return MediaKey(mediaMix32To64(type, dc), id); } struct DocumentAdditionalData { virtual ~DocumentAdditionalData() = default; }; struct StickerData : public DocumentAdditionalData { Data::FileOrigin setOrigin() const; std::unique_ptr image; bool animated = false; QString alt; MTPInputStickerSet set = MTP_inputStickerSetEmpty(); StorageImageLocation loc; // doc thumb location }; struct SongData : public DocumentAdditionalData { int32 duration = 0; QString title, performer; }; struct VoiceData : public DocumentAdditionalData { ~VoiceData(); int duration = 0; VoiceWaveform waveform; char wavemax = 0; }; bool fileIsImage(const QString &name, const QString &mime); namespace Serialize { class Document; } // namespace Serialize; class DocumentData { public: DocumentData(not_null owner, DocumentId id); [[nodiscard]] Data::Session &owner() const; [[nodiscard]] Main::Session &session() const; void setattributes( const QVector &attributes); void automaticLoad( Data::FileOrigin origin, const HistoryItem *item); void automaticLoadSettingsChanged(); enum class FilePathResolve { Cached, Checked, SaveFromData, SaveFromDataSilent, }; [[nodiscard]] bool loaded( FilePathResolve resolve = FilePathResolve::Cached) const; [[nodiscard]] bool loading() const; [[nodiscard]] QString loadingFilePath() const; [[nodiscard]] bool displayLoading() const; void save( Data::FileOrigin origin, const QString &toFile, LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal, bool autoLoading = false); void cancel(); [[nodiscard]] bool cancelled() const; [[nodiscard]] float64 progress() const; [[nodiscard]] int loadOffset() const; [[nodiscard]] bool uploading() const; [[nodiscard]] bool loadedInMediaCache() const; void setLoadedInMediaCache(bool loaded); void setWaitingForAlbum(); [[nodiscard]] bool waitingForAlbum() const; [[nodiscard]] QByteArray data() const; [[nodiscard]] const FileLocation &location(bool check = false) const; void setLocation(const FileLocation &loc); [[nodiscard]] QString filepath( FilePathResolve resolve = FilePathResolve::Cached) const; [[nodiscard]] bool saveToCache() const; void unload(); [[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin); [[nodiscard]] StickerData *sticker() const; void checkStickerLarge(); void checkStickerSmall(); [[nodiscard]] Image *getStickerSmall(); [[nodiscard]] Image *getStickerLarge(); [[nodiscard]] Data::FileOrigin stickerSetOrigin() const; [[nodiscard]] Data::FileOrigin stickerOrGifOrigin() const; [[nodiscard]] bool isStickerSetInstalled() const; [[nodiscard]] SongData *song(); [[nodiscard]] const SongData *song() const; [[nodiscard]] VoiceData *voice(); [[nodiscard]] const VoiceData *voice() const; [[nodiscard]] bool isVoiceMessage() const; [[nodiscard]] bool isVideoMessage() const; [[nodiscard]] bool isSong() const; [[nodiscard]] bool isAudioFile() const; [[nodiscard]] bool isVideoFile() const; [[nodiscard]] bool isAnimation() const; [[nodiscard]] bool isGifv() const; [[nodiscard]] bool isTheme() const; [[nodiscard]] bool isSharedMediaMusic() const; [[nodiscard]] TimeId getDuration() const; [[nodiscard]] bool isImage() const; void recountIsImage(); [[nodiscard]] bool supportsStreaming() const; void setNotSupportsStreaming(); void setData(const QByteArray &data) { _data = data; } void setDataAndCache(const QByteArray &data); bool checkWallPaperProperties(); [[nodiscard]] bool isWallPaper() const; [[nodiscard]] bool isPatternWallPaper() const; [[nodiscard]] bool hasThumbnail() const; void loadThumbnail(Data::FileOrigin origin); [[nodiscard]] Image *thumbnailInline() const; [[nodiscard]] Image *thumbnail() const; void updateThumbnails( ImagePtr thumbnailInline, ImagePtr thumbnail); [[nodiscard]] Image *goodThumbnail() const; [[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const; void setGoodThumbnailOnUpload(QImage &&image, QByteArray &&bytes); void refreshGoodThumbnail(); void replaceGoodThumbnail(std::unique_ptr &&source); [[nodiscard]] auto bigFileBaseCacheKey() const -> std::optional; void setRemoteLocation( int32 dc, uint64 access, const QByteArray &fileReference); void setContentUrl(const QString &url); void setWebLocation(const WebFileLocation &location); [[nodiscard]] bool hasRemoteLocation() const; [[nodiscard]] bool hasWebLocation() const; [[nodiscard]] bool isNull() const; [[nodiscard]] MTPInputDocument mtpInput() const; [[nodiscard]] QByteArray fileReference() const; void refreshFileReference(const QByteArray &value); void refreshStickerThumbFileReference(); // When we have some client-side generated document // (for example for displaying an external inline bot result) // and it has downloaded data, we can collect that data from it // to (this) received from the server "same" document. void collectLocalData(not_null local); [[nodiscard]] QString filename() const; [[nodiscard]] QString mimeString() const; [[nodiscard]] bool hasMimeType(QLatin1String mime) const; void setMimeString(const QString &mime); [[nodiscard]] MediaKey mediaKey() const; [[nodiscard]] Storage::Cache::Key cacheKey() const; [[nodiscard]] uint8 cacheTag() const; [[nodiscard]] static QString ComposeNameString( const QString &filename, const QString &songTitle, const QString &songPerformer); [[nodiscard]] QString composeNameString() const; [[nodiscard]] bool canBePlayed() const; [[nodiscard]] bool canBeStreamed() const; [[nodiscard]] auto createStreamingLoader( Data::FileOrigin origin, bool forceRemoteLoader) const -> std::unique_ptr; void setInappPlaybackFailed(); [[nodiscard]] bool inappPlaybackFailed() const; ~DocumentData(); DocumentId id = 0; DocumentType type = FileDocument; QSize dimensions; int32 date = 0; int32 size = 0; FileStatus status = FileReady; std::unique_ptr uploadingData; private: enum class Flag : uchar { StreamingMaybeYes = 0x01, StreamingMaybeNo = 0x02, StreamingPlaybackFailed = 0x04, ImageType = 0x08, DownloadCancelled = 0x10, LoadedInMediaCache = 0x20, }; using Flags = base::flags; friend constexpr bool is_flag_type(Flag) { return true; }; static constexpr Flags kStreamingSupportedMask = Flags() | Flag::StreamingMaybeYes | Flag::StreamingMaybeNo; static constexpr Flags kStreamingSupportedUnknown = Flags() | Flag::StreamingMaybeYes | Flag::StreamingMaybeNo; static constexpr Flags kStreamingSupportedMaybeYes = Flags() | Flag::StreamingMaybeYes; static constexpr Flags kStreamingSupportedMaybeNo = Flags() | Flag::StreamingMaybeNo; static constexpr Flags kStreamingSupportedNo = Flags(); friend class Serialize::Document; LocationType locationType() const; void validateLottieSticker(); void validateGoodThumbnail(); void setMaybeSupportsStreaming(bool supports); void setLoadedInMediaCacheLocation(); void destroyLoader() const; [[nodiscard]] bool useStreamingLoader() const; [[nodiscard]] bool thumbnailEnoughForSticker() const; // Two types of location: from MTProto by dc+access or from web by url int32 _dc = 0; uint64 _access = 0; QByteArray _fileReference; QString _url; QString _filename; QString _mimeString; WebFileLocation _urlLocation; ImagePtr _thumbnailInline; ImagePtr _thumbnail; std::unique_ptr _goodThumbnail; Data::ReplyPreview _replyPreview; not_null _owner; FileLocation _location; QByteArray _data; std::unique_ptr _additional; int32 _duration = -1; mutable Flags _flags = kStreamingSupportedUnknown; mutable std::unique_ptr _loader; }; VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform); class DocumentClickHandler : public FileClickHandler { public: DocumentClickHandler( not_null document, FullMsgId context = FullMsgId()); [[nodiscard]] bool valid() const { return !_session.empty(); } [[nodiscard]] not_null document() const { return _document; } private: const base::weak_ptr _session; const not_null _document; }; class DocumentSaveClickHandler : public DocumentClickHandler { public: enum class Mode { ToCacheOrFile, ToFile, ToNewFile, }; using DocumentClickHandler::DocumentClickHandler; static void Save( Data::FileOrigin origin, not_null document, Mode mode = Mode::ToCacheOrFile); protected: void onClickImpl() const override; }; class DocumentOpenClickHandler : public DocumentClickHandler { public: using DocumentClickHandler::DocumentClickHandler; static void Open( Data::FileOrigin origin, not_null document, HistoryItem *context); protected: void onClickImpl() const override; }; class DocumentCancelClickHandler : public DocumentClickHandler { public: using DocumentClickHandler::DocumentClickHandler; protected: void onClickImpl() const override; }; class DocumentOpenWithClickHandler : public DocumentClickHandler { public: using DocumentClickHandler::DocumentClickHandler; static void Open( Data::FileOrigin origin, not_null document); protected: void onClickImpl() const override; }; class VoiceSeekClickHandler : public DocumentOpenClickHandler { public: using DocumentOpenClickHandler::DocumentOpenClickHandler; protected: void onClickImpl() const override { } }; class DocumentWrappedClickHandler : public DocumentClickHandler { public: DocumentWrappedClickHandler( ClickHandlerPtr wrapped, not_null document, FullMsgId context = FullMsgId()) : DocumentClickHandler(document, context) , _wrapped(wrapped) { } protected: void onClickImpl() const override { _wrapped->onClick({ Qt::LeftButton }); } private: ClickHandlerPtr _wrapped; }; QString FileNameForSave( const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir()); namespace Data { QString FileExtension(const QString &filepath); bool IsValidMediaFile(const QString &filepath); bool IsExecutableName(const QString &filepath); base::binary_guard ReadImageAsync( not_null document, FnMut postprocess, FnMut done); } // namespace Data