1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "base/flags.h"
11 #include "base/binary_guard.h"
12 #include "data/data_types.h"
13 #include "data/data_cloud_file.h"
14 #include "core/file_location.h"
15 #include "ui/image/image.h"
16 
17 class mtpFileLoader;
18 
19 namespace Images {
20 class Source;
21 } // namespace Images
22 
23 namespace Storage {
24 namespace Cache {
25 struct Key;
26 } // namespace Cache
27 } // namespace Storage
28 
29 namespace Media {
30 namespace Streaming {
31 class Loader;
32 } // namespace Streaming
33 } // namespace Media
34 
35 namespace Data {
36 class Session;
37 class DocumentMedia;
38 class ReplyPreview;
39 } // namespace Data
40 
41 namespace Main {
42 class Session;
43 } // namespace Main
44 
mediaMix32To64(int32 a,int32 b)45 inline uint64 mediaMix32To64(int32 a, int32 b) {
46 	return (uint64(*reinterpret_cast<uint32*>(&a)) << 32)
47 		| uint64(*reinterpret_cast<uint32*>(&b));
48 }
49 
50 // version field removed from document.
mediaKey(LocationType type,int32 dc,const uint64 & id)51 inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
52 	return MediaKey(mediaMix32To64(type, dc), id);
53 }
54 
55 struct DocumentAdditionalData {
56 	virtual ~DocumentAdditionalData() = default;
57 
58 };
59 
60 struct StickerData : public DocumentAdditionalData {
61 	Data::FileOrigin setOrigin() const;
62 
63 	bool animated = false;
64 	QString alt;
65 	StickerSetIdentifier set;
66 };
67 
68 struct SongData : public DocumentAdditionalData {
69 	int32 duration = 0;
70 	QString title, performer;
71 
72 };
73 
74 struct VoiceData : public DocumentAdditionalData {
75 	~VoiceData();
76 
77 	int duration = 0;
78 	VoiceWaveform waveform;
79 	char wavemax = 0;
80 };
81 
82 namespace Serialize {
83 class Document;
84 } // namespace Serialize;
85 
86 class DocumentData final {
87 public:
88 	DocumentData(not_null<Data::Session*> owner, DocumentId id);
89 	~DocumentData();
90 
91 	[[nodiscard]] Data::Session &owner() const;
92 	[[nodiscard]] Main::Session &session() const;
93 
94 	void setattributes(
95 		const QVector<MTPDocumentAttribute> &attributes);
96 
97 	void automaticLoadSettingsChanged();
98 
99 	[[nodiscard]] bool loading() const;
100 	[[nodiscard]] QString loadingFilePath() const;
101 	[[nodiscard]] bool displayLoading() const;
102 	void save(
103 		Data::FileOrigin origin,
104 		const QString &toFile,
105 		LoadFromCloudSetting fromCloud = LoadFromCloudOrLocal,
106 		bool autoLoading = false);
107 	void cancel();
108 	[[nodiscard]] bool cancelled() const;
109 	[[nodiscard]] float64 progress() const;
110 	[[nodiscard]] int loadOffset() const;
111 	[[nodiscard]] bool uploading() const;
112 	[[nodiscard]] bool loadedInMediaCache() const;
113 	void setLoadedInMediaCache(bool loaded);
114 
115 	void setWaitingForAlbum();
116 	[[nodiscard]] bool waitingForAlbum() const;
117 
118 	[[nodiscard]] const Core::FileLocation &location(bool check = false) const;
119 	void setLocation(const Core::FileLocation &loc);
120 
121 	bool saveFromData();
122 	bool saveFromDataSilent();
123 	[[nodiscard]] QString filepath(bool check = false) const;
124 
125 	[[nodiscard]] bool saveToCache() const;
126 
127 	[[nodiscard]] Image *getReplyPreview(Data::FileOrigin origin);
128 	[[nodiscard]] bool replyPreviewLoaded() const;
129 
130 	[[nodiscard]] StickerData *sticker() const;
131 	[[nodiscard]] Data::FileOrigin stickerSetOrigin() const;
132 	[[nodiscard]] Data::FileOrigin stickerOrGifOrigin() const;
133 	[[nodiscard]] bool isStickerSetInstalled() const;
134 	[[nodiscard]] SongData *song();
135 	[[nodiscard]] const SongData *song() const;
136 	[[nodiscard]] VoiceData *voice();
137 	[[nodiscard]] const VoiceData *voice() const;
138 
139 	[[nodiscard]] bool isVoiceMessage() const;
140 	[[nodiscard]] bool isVideoMessage() const;
141 	[[nodiscard]] bool isSong() const;
142 	[[nodiscard]] bool isSongWithCover() const;
143 	[[nodiscard]] bool isAudioFile() const;
144 	[[nodiscard]] bool isVideoFile() const;
145 	[[nodiscard]] bool isAnimation() const;
146 	[[nodiscard]] bool isGifv() const;
147 	[[nodiscard]] bool isTheme() const;
148 	[[nodiscard]] bool isSharedMediaMusic() const;
149 	[[nodiscard]] TimeId getDuration() const;
150 	[[nodiscard]] bool isImage() const;
151 	void recountIsImage();
152 	[[nodiscard]] bool supportsStreaming() const;
153 	void setNotSupportsStreaming();
154 	void setDataAndCache(const QByteArray &data);
155 	bool checkWallPaperProperties();
156 	[[nodiscard]] bool isWallPaper() const;
157 	[[nodiscard]] bool isPatternWallPaper() const;
158 	[[nodiscard]] bool isPatternWallPaperPNG() const;
159 	[[nodiscard]] bool isPatternWallPaperSVG() const;
160 
161 	[[nodiscard]] bool hasThumbnail() const;
162 	[[nodiscard]] bool thumbnailLoading() const;
163 	[[nodiscard]] bool thumbnailFailed() const;
164 	void loadThumbnail(Data::FileOrigin origin);
165 	[[nodiscard]] const ImageLocation &thumbnailLocation() const;
166 	[[nodiscard]] int thumbnailByteSize() const;
167 
168 	[[nodiscard]] bool hasVideoThumbnail() const;
169 	[[nodiscard]] bool videoThumbnailLoading() const;
170 	[[nodiscard]] bool videoThumbnailFailed() const;
171 	void loadVideoThumbnail(Data::FileOrigin origin);
172 	[[nodiscard]] const ImageLocation &videoThumbnailLocation() const;
173 	[[nodiscard]] int videoThumbnailByteSize() const;
174 
175 	void updateThumbnails(
176 		const InlineImageLocation &inlineThumbnail,
177 		const ImageWithLocation &thumbnail,
178 		const ImageWithLocation &videoThumbnail);
179 
inlineThumbnailBytes()180 	[[nodiscard]] QByteArray inlineThumbnailBytes() const {
181 		return _inlineThumbnailBytes;
182 	}
inlineThumbnailIsPath()183 	[[nodiscard]] bool inlineThumbnailIsPath() const {
184 		return (_flags & Flag::InlineThumbnailIsPath);
185 	}
clearInlineThumbnailBytes()186 	void clearInlineThumbnailBytes() {
187 		_inlineThumbnailBytes = QByteArray();
188 	}
189 
190 	[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
191 	[[nodiscard]] bool goodThumbnailChecked() const;
192 	[[nodiscard]] bool goodThumbnailGenerating() const;
193 	[[nodiscard]] bool goodThumbnailNoData() const;
194 	void setGoodThumbnailGenerating();
195 	void setGoodThumbnailDataReady();
196 	void setGoodThumbnailChecked(bool hasData);
197 
198 	[[nodiscard]] std::shared_ptr<Data::DocumentMedia> createMediaView();
199 	[[nodiscard]] auto activeMediaView() const
200 		-> std::shared_ptr<Data::DocumentMedia>;
201 	void setGoodThumbnailPhoto(not_null<PhotoData*> photo);
202 	[[nodiscard]] PhotoData *goodThumbnailPhoto() const;
203 
204 	[[nodiscard]] Storage::Cache::Key bigFileBaseCacheKey() const;
205 
206 	void setRemoteLocation(
207 		int32 dc,
208 		uint64 access,
209 		const QByteArray &fileReference);
210 	void setContentUrl(const QString &url);
211 	void setWebLocation(const WebFileLocation &location);
212 	[[nodiscard]] bool hasRemoteLocation() const;
213 	[[nodiscard]] bool hasWebLocation() const;
214 	[[nodiscard]] bool isNull() const;
215 	[[nodiscard]] MTPInputDocument mtpInput() const;
216 	[[nodiscard]] QByteArray fileReference() const;
217 	void refreshFileReference(const QByteArray &value);
218 
219 	// When we have some client-side generated document
220 	// (for example for displaying an external inline bot result)
221 	// and it has downloaded data, we can collect that data from it
222 	// to (this) received from the server "same" document.
223 	void collectLocalData(not_null<DocumentData*> local);
224 
225 	[[nodiscard]] QString filename() const;
226 	[[nodiscard]] QString mimeString() const;
227 	[[nodiscard]] bool hasMimeType(QLatin1String mime) const;
228 	void setMimeString(const QString &mime);
229 
230 	[[nodiscard]] bool hasAttachedStickers() const;
231 
232 	[[nodiscard]] MediaKey mediaKey() const;
233 	[[nodiscard]] Storage::Cache::Key cacheKey() const;
234 	[[nodiscard]] uint8 cacheTag() const;
235 
236 	[[nodiscard]] bool canBeStreamed() const;
237 	[[nodiscard]] auto createStreamingLoader(
238 		Data::FileOrigin origin,
239 		bool forceRemoteLoader) const
240 	-> std::unique_ptr<Media::Streaming::Loader>;
241 	[[nodiscard]] bool useStreamingLoader() const;
242 
243 	void setInappPlaybackFailed();
244 	[[nodiscard]] bool inappPlaybackFailed() const;
245 
246 	DocumentId id = 0;
247 	DocumentType type = FileDocument;
248 	QSize dimensions;
249 	int32 date = 0;
250 	int32 size = 0;
251 
252 	FileStatus status = FileReady;
253 
254 	std::unique_ptr<Data::UploadState> uploadingData;
255 
256 private:
257 	enum class Flag : uchar {
258 		StreamingMaybeYes = 0x01,
259 		StreamingMaybeNo = 0x02,
260 		StreamingPlaybackFailed = 0x04,
261 		ImageType = 0x08,
262 		DownloadCancelled = 0x10,
263 		LoadedInMediaCache = 0x20,
264 		HasAttachedStickers = 0x40,
265 		InlineThumbnailIsPath = 0x80,
266 	};
267 	using Flags = base::flags<Flag>;
is_flag_type(Flag)268 	friend constexpr bool is_flag_type(Flag) { return true; };
269 
270 	enum class GoodThumbnailFlag : uchar {
271 		Checked = 0x01,
272 		Generating = 0x02,
273 		NoData = 0x03,
274 		Mask = 0x03,
275 
276 		DataReady = 0x04,
277 	};
278 	using GoodThumbnailState = base::flags<GoodThumbnailFlag>;
is_flag_type(GoodThumbnailFlag)279 	friend constexpr bool is_flag_type(GoodThumbnailFlag) { return true; };
280 
281 	static constexpr Flags kStreamingSupportedMask = Flags()
282 		| Flag::StreamingMaybeYes
283 		| Flag::StreamingMaybeNo;
284 	static constexpr Flags kStreamingSupportedUnknown = Flags()
285 		| Flag::StreamingMaybeYes
286 		| Flag::StreamingMaybeNo;
287 	static constexpr Flags kStreamingSupportedMaybeYes = Flags()
288 		| Flag::StreamingMaybeYes;
289 	static constexpr Flags kStreamingSupportedMaybeNo = Flags()
290 		| Flag::StreamingMaybeNo;
291 	static constexpr Flags kStreamingSupportedNo = Flags();
292 
293 	friend class Serialize::Document;
294 
295 	[[nodiscard]] LocationType locationType() const;
296 	void validateLottieSticker();
297 	void setMaybeSupportsStreaming(bool supports);
298 	void setLoadedInMediaCacheLocation();
299 	void setFileName(const QString &remoteFileName);
300 
301 	void finishLoad();
302 	void handleLoaderUpdates();
303 	void destroyLoader();
304 
305 	bool saveFromDataChecked();
306 
307 	const not_null<Data::Session*> _owner;
308 
309 	// Two types of location: from MTProto by dc+access or from web by url
310 	int32 _dc = 0;
311 	uint64 _access = 0;
312 	QByteArray _fileReference;
313 	QString _url;
314 	QString _filename;
315 	QString _mimeString;
316 	WebFileLocation _urlLocation;
317 
318 	QByteArray _inlineThumbnailBytes;
319 	Data::CloudFile _thumbnail;
320 	Data::CloudFile _videoThumbnail;
321 	std::unique_ptr<Data::ReplyPreview> _replyPreview;
322 	std::weak_ptr<Data::DocumentMedia> _media;
323 	PhotoData *_goodThumbnailPhoto = nullptr;
324 
325 	Core::FileLocation _location;
326 	std::unique_ptr<DocumentAdditionalData> _additional;
327 	int32 _duration = -1;
328 	mutable Flags _flags = kStreamingSupportedUnknown;
329 	GoodThumbnailState _goodThumbnailState = GoodThumbnailState();
330 	std::unique_ptr<FileLoader> _loader;
331 
332 };
333 
334 VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit);
335 QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform);
336 
337 QString FileNameForSave(
338 	not_null<Main::Session*> session,
339 	const QString &title,
340 	const QString &filter,
341 	const QString &prefix,
342 	QString name,
343 	bool savingAs,
344 	const QDir &dir = QDir());
345 
346 QString DocumentFileNameForSave(
347 	not_null<const DocumentData*> data,
348 	bool forceSavingAs = false,
349 	const QString &already = QString(),
350 	const QDir &dir = QDir());
351