Fix crash in DocumentData destructor.
Keep AuthSession pointer in DocumentData for loader destruction.
This commit is contained in:
		
							parent
							
								
									63c1212ef1
								
							
						
					
					
						commit
						a858ab5d0b
					
				
					 8 changed files with 187 additions and 180 deletions
				
			
		|  | @ -268,14 +268,14 @@ AuthSession &Auth() { | ||||||
| AuthSession::AuthSession(UserId userId) | AuthSession::AuthSession(UserId userId) | ||||||
| : _userId(userId) | : _userId(userId) | ||||||
| , _autoLockTimer([this] { checkAutoLock(); }) | , _autoLockTimer([this] { checkAutoLock(); }) | ||||||
| , _data(std::make_unique<Data::Session>(this)) |  | ||||||
| , _api(std::make_unique<ApiWrap>(this)) | , _api(std::make_unique<ApiWrap>(this)) | ||||||
| , _calls(std::make_unique<Calls::Instance>()) | , _calls(std::make_unique<Calls::Instance>()) | ||||||
| , _downloader(std::make_unique<Storage::Downloader>()) | , _downloader(std::make_unique<Storage::Downloader>()) | ||||||
| , _uploader(std::make_unique<Storage::Uploader>()) | , _uploader(std::make_unique<Storage::Uploader>()) | ||||||
| , _storage(std::make_unique<Storage::Facade>()) | , _storage(std::make_unique<Storage::Facade>()) | ||||||
| , _notifications(std::make_unique<Window::Notifications::System>(this)) | , _notifications(std::make_unique<Window::Notifications::System>(this)) | ||||||
| , _changelogs(Core::Changelogs::Create(this)) { | , _changelogs(Core::Changelogs::Create(this)) | ||||||
|  | , _data(std::make_unique<Data::Session>(this)) { | ||||||
| 	Expects(_userId != 0); | 	Expects(_userId != 0); | ||||||
| 
 | 
 | ||||||
| 	_saveDataTimer.setCallback([this] { | 	_saveDataTimer.setCallback([this] { | ||||||
|  |  | ||||||
|  | @ -252,7 +252,6 @@ private: | ||||||
| 	TimeMs _shouldLockAt = 0; | 	TimeMs _shouldLockAt = 0; | ||||||
| 	base::Timer _autoLockTimer; | 	base::Timer _autoLockTimer; | ||||||
| 
 | 
 | ||||||
| 	const std::unique_ptr<Data::Session> _data; |  | ||||||
| 	const std::unique_ptr<ApiWrap> _api; | 	const std::unique_ptr<ApiWrap> _api; | ||||||
| 	const std::unique_ptr<Calls::Instance> _calls; | 	const std::unique_ptr<Calls::Instance> _calls; | ||||||
| 	const std::unique_ptr<Storage::Downloader> _downloader; | 	const std::unique_ptr<Storage::Downloader> _downloader; | ||||||
|  | @ -261,6 +260,9 @@ private: | ||||||
| 	const std::unique_ptr<Window::Notifications::System> _notifications; | 	const std::unique_ptr<Window::Notifications::System> _notifications; | ||||||
| 	const std::unique_ptr<Core::Changelogs> _changelogs; | 	const std::unique_ptr<Core::Changelogs> _changelogs; | ||||||
| 
 | 
 | ||||||
|  | 	// _data depends on _downloader / _uploader, including destructor.
 | ||||||
|  | 	const std::unique_ptr<Data::Session> _data; | ||||||
|  | 
 | ||||||
| 	rpl::lifetime _lifetime; | 	rpl::lifetime _lifetime; | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -152,28 +152,6 @@ QString saveFileName(const QString &title, const QString &filter, const QString | ||||||
| 	return name; | 	return name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool StickerData::setInstalled() const { |  | ||||||
| 	switch (set.type()) { |  | ||||||
| 	case mtpc_inputStickerSetID: { |  | ||||||
| 		auto it = Auth().data().stickerSets().constFind( |  | ||||||
| 			set.c_inputStickerSetID().vid.v); |  | ||||||
| 		return (it != Auth().data().stickerSets().cend()) |  | ||||||
| 			&& !(it->flags & MTPDstickerSet::Flag::f_archived) |  | ||||||
| 			&& (it->flags & MTPDstickerSet::Flag::f_installed_date); |  | ||||||
| 	} break; |  | ||||||
| 	case mtpc_inputStickerSetShortName: { |  | ||||||
| 		auto name = qs(set.c_inputStickerSetShortName().vshort_name).toLower(); |  | ||||||
| 		for (auto it = Auth().data().stickerSets().cbegin(), e = Auth().data().stickerSets().cend(); it != e; ++it) { |  | ||||||
| 			if (it->shortName.toLower() == name) { |  | ||||||
| 				return !(it->flags & MTPDstickerSet::Flag::f_archived) |  | ||||||
| 					&& (it->flags & MTPDstickerSet::Flag::f_installed_date); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} break; |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = false, const QString already = QString(), const QDir &dir = QDir()) { | QString documentSaveFilename(const DocumentData *data, bool forceSavingAs = false, const QString already = QString(), const QDir &dir = QDir()) { | ||||||
| 	auto alreadySavingFilename = data->loadingFilePath(); | 	auto alreadySavingFilename = data->loadingFilePath(); | ||||||
| 	if (!alreadySavingFilename.isEmpty()) { | 	if (!alreadySavingFilename.isEmpty()) { | ||||||
|  | @ -253,9 +231,7 @@ void DocumentOpenClickHandler::doOpen( | ||||||
| 				auto audio = AudioMsgId(data, msgId); | 				auto audio = AudioMsgId(data, msgId); | ||||||
| 				Media::Player::mixer()->play(audio); | 				Media::Player::mixer()->play(audio); | ||||||
| 				Media::Player::Updated().notify(audio); | 				Media::Player::Updated().notify(audio); | ||||||
| 				if (App::main()) { | 				data->session()->data().markMediaRead(data); | ||||||
| 					Auth().data().markMediaRead(data); |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		} else if (playMusic) { | 		} else if (playMusic) { | ||||||
| 			auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song); | 			auto state = Media::Player::mixer()->currentState(AudioMsgId::Type::Song); | ||||||
|  | @ -282,24 +258,24 @@ void DocumentOpenClickHandler::doOpen( | ||||||
| 					File::Launch(filepath); | 					File::Launch(filepath); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			Auth().data().markMediaRead(data); | 			data->session()->data().markMediaRead(data); | ||||||
| 		} else if (data->isVoiceMessage() || data->isAudioFile() || data->isVideoFile()) { | 		} else if (data->isVoiceMessage() || data->isAudioFile() || data->isVideoFile()) { | ||||||
| 			auto filepath = location.name(); | 			auto filepath = location.name(); | ||||||
| 			if (documentIsValidMediaFile(filepath)) { | 			if (documentIsValidMediaFile(filepath)) { | ||||||
| 				File::Launch(filepath); | 				File::Launch(filepath); | ||||||
| 			} | 			} | ||||||
| 			Auth().data().markMediaRead(data); | 			data->session()->data().markMediaRead(data); | ||||||
| 		} else if (data->size < App::kImageSizeLimit) { | 		} else if (data->size < App::kImageSizeLimit) { | ||||||
| 			if (!data->data().isEmpty() && playAnimation) { | 			if (!data->data().isEmpty() && playAnimation) { | ||||||
| 				if (action == ActionOnLoadPlayInline && context) { | 				if (action == ActionOnLoadPlayInline && context) { | ||||||
| 					Auth().data().requestAnimationPlayInline(context); | 					data->session()->data().requestAnimationPlayInline(context); | ||||||
| 				} else { | 				} else { | ||||||
| 					Messenger::Instance().showDocument(data, context); | 					Messenger::Instance().showDocument(data, context); | ||||||
| 				} | 				} | ||||||
| 			} else if (location.accessEnable()) { | 			} else if (location.accessEnable()) { | ||||||
| 				if (playAnimation || QImageReader(location.name()).canRead()) { | 				if (playAnimation || QImageReader(location.name()).canRead()) { | ||||||
| 					if (playAnimation && action == ActionOnLoadPlayInline && context) { | 					if (playAnimation && action == ActionOnLoadPlayInline && context) { | ||||||
| 						Auth().data().requestAnimationPlayInline(context); | 						data->session()->data().requestAnimationPlayInline(context); | ||||||
| 					} else { | 					} else { | ||||||
| 						Messenger::Instance().showDocument(data, context); | 						Messenger::Instance().showDocument(data, context); | ||||||
| 					} | 					} | ||||||
|  | @ -378,35 +354,22 @@ void DocumentCancelClickHandler::onClickImpl() const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VoiceData::~VoiceData() { | VoiceData::~VoiceData() { | ||||||
| 	if (!waveform.isEmpty() && waveform.at(0) == -1 && waveform.size() > int32(sizeof(TaskId))) { | 	if (!waveform.isEmpty() | ||||||
|  | 		&& waveform[0] == -1 | ||||||
|  | 		&& waveform.size() > int32(sizeof(TaskId))) { | ||||||
| 		TaskId taskId = 0; | 		TaskId taskId = 0; | ||||||
| 		memcpy(&taskId, waveform.constData() + 1, sizeof(taskId)); | 		memcpy(&taskId, waveform.constData() + 1, sizeof(taskId)); | ||||||
| 		Local::cancelTask(taskId); | 		Local::cancelTask(taskId); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QString &url, const QVector<MTPDocumentAttribute> &attributes) | DocumentData::DocumentData(DocumentId id, not_null<AuthSession*> session) | ||||||
| : id(id) | : id(id) | ||||||
| , _dc(dc) | , _session(session) { | ||||||
| , _access(accessHash) |  | ||||||
| , _version(version) |  | ||||||
| , _url(url) { |  | ||||||
| 	setattributes(attributes); |  | ||||||
| 	if (_dc && _access) { |  | ||||||
| 		_location = Local::readFileLocation(mediaKey()); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DocumentData *DocumentData::create(DocumentId id) { | not_null<AuthSession*> DocumentData::session() const { | ||||||
| 	return new DocumentData(id, 0, 0, 0, QString(), QVector<MTPDocumentAttribute>()); | 	return _session; | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DocumentData *DocumentData::create(DocumentId id, int32 dc, uint64 accessHash, int32 version, const QVector<MTPDocumentAttribute> &attributes) { |  | ||||||
| 	return new DocumentData(id, dc, accessHash, version, QString(), attributes); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| DocumentData *DocumentData::create(DocumentId id, const QString &url, const QVector<MTPDocumentAttribute> &attributes) { |  | ||||||
| 	return new DocumentData(id, 0, 0, 0, url, attributes); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) { | void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) { | ||||||
|  | @ -577,7 +540,7 @@ void DocumentData::performActionOnLoad() { | ||||||
| 				} | 				} | ||||||
| 			} else if (Media::Player::IsStopped(state.state)) { | 			} else if (Media::Player::IsStopped(state.state)) { | ||||||
| 				Media::Player::mixer()->play(AudioMsgId(this, _actionOnLoadMsgId)); | 				Media::Player::mixer()->play(AudioMsgId(this, _actionOnLoadMsgId)); | ||||||
| 				Auth().data().markMediaRead(this); | 				_session->data().markMediaRead(this); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else if (playMusic) { | 	} else if (playMusic) { | ||||||
|  | @ -598,7 +561,7 @@ void DocumentData::performActionOnLoad() { | ||||||
| 	} else if (playAnimation) { | 	} else if (playAnimation) { | ||||||
| 		if (loaded()) { | 		if (loaded()) { | ||||||
| 			if (_actionOnLoad == ActionOnLoadPlayInline && item) { | 			if (_actionOnLoad == ActionOnLoadPlayInline && item) { | ||||||
| 				Auth().data().requestAnimationPlayInline(item); | 				_session->data().requestAnimationPlayInline(item); | ||||||
| 			} else { | 			} else { | ||||||
| 				Messenger::Instance().showDocument(this, item); | 				Messenger::Instance().showDocument(this, item); | ||||||
| 			} | 			} | ||||||
|  | @ -613,7 +576,7 @@ void DocumentData::performActionOnLoad() { | ||||||
| 				if (documentIsValidMediaFile(already)) { | 				if (documentIsValidMediaFile(already)) { | ||||||
| 					File::Launch(already); | 					File::Launch(already); | ||||||
| 				} | 				} | ||||||
| 				Auth().data().markMediaRead(this); | 				_session->data().markMediaRead(this); | ||||||
| 			} else if (loc.accessEnable()) { | 			} else if (loc.accessEnable()) { | ||||||
| 				if (showImage && QImageReader(loc.name()).canRead()) { | 				if (showImage && QImageReader(loc.name()).canRead()) { | ||||||
| 					Messenger::Instance().showDocument(this, item); | 					Messenger::Instance().showDocument(this, item); | ||||||
|  | @ -642,7 +605,7 @@ bool DocumentData::loaded(FilePathResolveType type) const { | ||||||
| 			} | 			} | ||||||
| 			destroyLoaderDelayed(); | 			destroyLoaderDelayed(); | ||||||
| 		} | 		} | ||||||
| 		Auth().data().notifyDocumentLayoutChanged(this); | 		_session->data().notifyDocumentLayoutChanged(this); | ||||||
| 	} | 	} | ||||||
| 	return !data().isEmpty() || !filepath(type).isEmpty(); | 	return !data().isEmpty() || !filepath(type).isEmpty(); | ||||||
| } | } | ||||||
|  | @ -650,7 +613,7 @@ bool DocumentData::loaded(FilePathResolveType type) const { | ||||||
| void DocumentData::destroyLoaderDelayed(mtpFileLoader *newValue) const { | void DocumentData::destroyLoaderDelayed(mtpFileLoader *newValue) const { | ||||||
| 	_loader->stop(); | 	_loader->stop(); | ||||||
| 	auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, newValue)); | 	auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, newValue)); | ||||||
| 	Auth().downloader().delayedDestroyLoader(std::move(loader)); | 	_session->downloader().delayedDestroyLoader(std::move(loader)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool DocumentData::loading() const { | bool DocumentData::loading() const { | ||||||
|  | @ -752,7 +715,7 @@ void DocumentData::save( | ||||||
| 		_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool))); | 		_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool))); | ||||||
| 		_loader->start(); | 		_loader->start(); | ||||||
| 	} | 	} | ||||||
| 	Auth().data().notifyDocumentLayoutChanged(this); | 	_session->data().notifyDocumentLayoutChanged(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DocumentData::cancel() { | void DocumentData::cancel() { | ||||||
|  | @ -763,9 +726,8 @@ void DocumentData::cancel() { | ||||||
| 	auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, CancelledMtpFileLoader)); | 	auto loader = std::unique_ptr<FileLoader>(std::exchange(_loader, CancelledMtpFileLoader)); | ||||||
| 	loader->cancel(); | 	loader->cancel(); | ||||||
| 	loader->stop(); | 	loader->stop(); | ||||||
| 	Auth().downloader().delayedDestroyLoader(std::move(loader)); | 	_session->downloader().delayedDestroyLoader(std::move(loader)); | ||||||
| 
 | 	_session->data().notifyDocumentLayoutChanged(this); | ||||||
| 	Auth().data().notifyDocumentLayoutChanged(this); |  | ||||||
| 	if (auto main = App::main()) { | 	if (auto main = App::main()) { | ||||||
| 		main->documentLoadProgress(this); | 		main->documentLoadProgress(this); | ||||||
| 	} | 	} | ||||||
|  | @ -870,6 +832,31 @@ QString DocumentData::filepath(FilePathResolveType type, bool forceSavingAs) con | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool DocumentData::isStickerSetInstalled() const { | ||||||
|  | 	Expects(sticker() != nullptr); | ||||||
|  | 
 | ||||||
|  | 	const auto &set = sticker()->set; | ||||||
|  | 	const auto &sets = _session->data().stickerSets(); | ||||||
|  | 	switch (set.type()) { | ||||||
|  | 	case mtpc_inputStickerSetID: { | ||||||
|  | 		auto it = sets.constFind(set.c_inputStickerSetID().vid.v); | ||||||
|  | 		return (it != sets.cend()) | ||||||
|  | 			&& !(it->flags & MTPDstickerSet::Flag::f_archived) | ||||||
|  | 			&& (it->flags & MTPDstickerSet::Flag::f_installed_date); | ||||||
|  | 	} break; | ||||||
|  | 	case mtpc_inputStickerSetShortName: { | ||||||
|  | 		auto name = qs(set.c_inputStickerSetShortName().vshort_name).toLower(); | ||||||
|  | 		for (auto it = sets.cbegin(), e = sets.cend(); it != e; ++it) { | ||||||
|  | 			if (it->shortName.toLower() == name) { | ||||||
|  | 				return !(it->flags & MTPDstickerSet::Flag::f_archived) | ||||||
|  | 					&& (it->flags & MTPDstickerSet::Flag::f_installed_date); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} break; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ImagePtr DocumentData::makeReplyPreview() { | ImagePtr DocumentData::makeReplyPreview() { | ||||||
| 	if (replyPreview->isNull() && !thumb->isNull()) { | 	if (replyPreview->isNull() && !thumb->isNull()) { | ||||||
| 		if (thumb->loaded()) { | 		if (thumb->loaded()) { | ||||||
|  | @ -889,6 +876,105 @@ ImagePtr DocumentData::makeReplyPreview() { | ||||||
| 	return replyPreview; | 	return replyPreview; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | StickerData *DocumentData::sticker() const { | ||||||
|  | 	return (type == StickerDocument) | ||||||
|  | 		? static_cast<StickerData*>(_additional.get()) | ||||||
|  | 		: nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DocumentData::checkSticker() { | ||||||
|  | 	const auto data = sticker(); | ||||||
|  | 	if (!data) return; | ||||||
|  | 
 | ||||||
|  | 	automaticLoad(nullptr); | ||||||
|  | 	if (data->img->isNull() && loaded()) { | ||||||
|  | 		if (_data.isEmpty()) { | ||||||
|  | 			const FileLocation &loc(location(true)); | ||||||
|  | 			if (loc.accessEnable()) { | ||||||
|  | 				data->img = ImagePtr(loc.name()); | ||||||
|  | 				loc.accessDisable(); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			data->img = ImagePtr(_data); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SongData *DocumentData::song() { | ||||||
|  | 	return isSong() | ||||||
|  | 		? static_cast<SongData*>(_additional.get()) | ||||||
|  | 		: nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const SongData *DocumentData::song() const { | ||||||
|  | 	return const_cast<DocumentData*>(this)->song(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | VoiceData *DocumentData::voice() { | ||||||
|  | 	return isVoiceMessage() | ||||||
|  | 		? static_cast<VoiceData*>(_additional.get()) | ||||||
|  | 		: nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const VoiceData *DocumentData::voice() const { | ||||||
|  | 	return const_cast<DocumentData*>(this)->voice(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool DocumentData::hasRemoteLocation() const { | ||||||
|  | 	return (_dc != 0 && _access != 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool DocumentData::isValid() const { | ||||||
|  | 	return hasRemoteLocation() || !_url.isEmpty(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MTPInputDocument DocumentData::mtpInput() const { | ||||||
|  | 	if (_access) { | ||||||
|  | 		return MTP_inputDocument( | ||||||
|  | 			MTP_long(id), | ||||||
|  | 			MTP_long(_access)); | ||||||
|  | 	} | ||||||
|  | 	return MTP_inputDocumentEmpty(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString DocumentData::filename() const { | ||||||
|  | 	return _filename; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString DocumentData::mimeString() const { | ||||||
|  | 	return _mimeString; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool DocumentData::hasMimeType(QLatin1String mime) const { | ||||||
|  | 	return !_mimeString.compare(mime, Qt::CaseInsensitive); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DocumentData::setMimeString(const QString &mime) { | ||||||
|  | 	_mimeString = mime; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MediaKey DocumentData::mediaKey() const { | ||||||
|  | 	return ::mediaKey(locationType(), _dc, id, _version); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | QString DocumentData::composeNameString() const { | ||||||
|  | 	if (auto songData = song()) { | ||||||
|  | 		return ComposeNameString( | ||||||
|  | 			_filename, | ||||||
|  | 			songData->title, | ||||||
|  | 			songData->performer); | ||||||
|  | 	} | ||||||
|  | 	return ComposeNameString(_filename, QString(), QString()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LocationType DocumentData::locationType() const { | ||||||
|  | 	return isVoiceMessage() | ||||||
|  | 		? AudioFileLocation | ||||||
|  | 		: isVideoFile() | ||||||
|  | 		? VideoFileLocation | ||||||
|  | 		: DocumentFileLocation; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool DocumentData::isVoiceMessage() const { | bool DocumentData::isVoiceMessage() const { | ||||||
| 	return (type == VoiceDocument); | 	return (type == VoiceDocument); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| 
 | 
 | ||||||
| #include "data/data_types.h" | #include "data/data_types.h" | ||||||
| 
 | 
 | ||||||
|  | class AuthSession; | ||||||
|  | 
 | ||||||
| inline uint64 mediaMix32To64(int32 a, int32 b) { | inline uint64 mediaMix32To64(int32 a, int32 b) { | ||||||
| 	return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | 	return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | ||||||
| 		| uint64(*reinterpret_cast<uint32*>(&b)); | 		| uint64(*reinterpret_cast<uint32*>(&b)); | ||||||
|  | @ -42,10 +44,7 @@ struct DocumentAdditionalData { | ||||||
| struct StickerData : public DocumentAdditionalData { | struct StickerData : public DocumentAdditionalData { | ||||||
| 	ImagePtr img; | 	ImagePtr img; | ||||||
| 	QString alt; | 	QString alt; | ||||||
| 
 |  | ||||||
| 	MTPInputStickerSet set = MTP_inputStickerSetEmpty(); | 	MTPInputStickerSet set = MTP_inputStickerSetEmpty(); | ||||||
| 	bool setInstalled() const; |  | ||||||
| 
 |  | ||||||
| 	StorageImageLocation loc; // doc thumb location
 | 	StorageImageLocation loc; // doc thumb location
 | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  | @ -72,17 +71,9 @@ class Document; | ||||||
| 
 | 
 | ||||||
| class DocumentData { | class DocumentData { | ||||||
| public: | public: | ||||||
| 	static DocumentData *create(DocumentId id); | 	DocumentData(DocumentId id, not_null<AuthSession*> session); | ||||||
| 	static DocumentData *create( | 
 | ||||||
| 		DocumentId id, | 	not_null<AuthSession*> session() const; | ||||||
| 		int32 dc, |  | ||||||
| 		uint64 accessHash, |  | ||||||
| 		int32 version, |  | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes); |  | ||||||
| 	static DocumentData *create( |  | ||||||
| 		DocumentId id, |  | ||||||
| 		const QString &url, |  | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes); |  | ||||||
| 
 | 
 | ||||||
| 	void setattributes( | 	void setattributes( | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes); | 		const QVector<MTPDocumentAttribute> &attributes); | ||||||
|  | @ -130,44 +121,14 @@ public: | ||||||
| 	void forget(); | 	void forget(); | ||||||
| 	ImagePtr makeReplyPreview(); | 	ImagePtr makeReplyPreview(); | ||||||
| 
 | 
 | ||||||
| 	StickerData *sticker() { | 	StickerData *sticker() const; | ||||||
| 		return (type == StickerDocument) | 	void checkSticker(); | ||||||
| 			? static_cast<StickerData*>(_additional.get()) | 	bool isStickerSetInstalled() const; | ||||||
| 			: nullptr; | 	SongData *song(); | ||||||
| 	} | 	const SongData *song() const; | ||||||
| 	void checkSticker() { | 	VoiceData *voice(); | ||||||
| 		StickerData *s = sticker(); | 	const VoiceData *voice() const; | ||||||
| 		if (!s) return; |  | ||||||
| 
 | 
 | ||||||
| 		automaticLoad(nullptr); |  | ||||||
| 		if (s->img->isNull() && loaded()) { |  | ||||||
| 			if (_data.isEmpty()) { |  | ||||||
| 				const FileLocation &loc(location(true)); |  | ||||||
| 				if (loc.accessEnable()) { |  | ||||||
| 					s->img = ImagePtr(loc.name()); |  | ||||||
| 					loc.accessDisable(); |  | ||||||
| 				} |  | ||||||
| 			} else { |  | ||||||
| 				s->img = ImagePtr(_data); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	SongData *song() { |  | ||||||
| 		return isSong() |  | ||||||
| 			? static_cast<SongData*>(_additional.get()) |  | ||||||
| 			: nullptr; |  | ||||||
| 	} |  | ||||||
| 	const SongData *song() const { |  | ||||||
| 		return const_cast<DocumentData*>(this)->song(); |  | ||||||
| 	} |  | ||||||
| 	VoiceData *voice() { |  | ||||||
| 		return isVoiceMessage() |  | ||||||
| 			? static_cast<VoiceData*>(_additional.get()) |  | ||||||
| 			: nullptr; |  | ||||||
| 	} |  | ||||||
| 	const VoiceData *voice() const { |  | ||||||
| 		return const_cast<DocumentData*>(this)->voice(); |  | ||||||
| 	} |  | ||||||
| 	bool isVoiceMessage() const; | 	bool isVoiceMessage() const; | ||||||
| 	bool isVideoMessage() const; | 	bool isVideoMessage() const; | ||||||
| 	bool isSong() const; | 	bool isSong() const; | ||||||
|  | @ -187,20 +148,9 @@ public: | ||||||
| 	bool setRemoteVersion(int32 version); // Returns true if version has changed.
 | 	bool setRemoteVersion(int32 version); // Returns true if version has changed.
 | ||||||
| 	void setRemoteLocation(int32 dc, uint64 access); | 	void setRemoteLocation(int32 dc, uint64 access); | ||||||
| 	void setContentUrl(const QString &url); | 	void setContentUrl(const QString &url); | ||||||
| 	bool hasRemoteLocation() const { | 	bool hasRemoteLocation() const; | ||||||
| 		return (_dc != 0 && _access != 0); | 	bool isValid() const; | ||||||
| 	} | 	MTPInputDocument mtpInput() const; | ||||||
| 	bool isValid() const { |  | ||||||
| 		return hasRemoteLocation() || !_url.isEmpty(); |  | ||||||
| 	} |  | ||||||
| 	MTPInputDocument mtpInput() const { |  | ||||||
| 		if (_access) { |  | ||||||
| 			return MTP_inputDocument( |  | ||||||
| 				MTP_long(id), |  | ||||||
| 				MTP_long(_access)); |  | ||||||
| 		} |  | ||||||
| 		return MTP_inputDocumentEmpty(); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	// When we have some client-side generated document
 | 	// When we have some client-side generated document
 | ||||||
| 	// (for example for displaying an external inline bot result)
 | 	// (for example for displaying an external inline bot result)
 | ||||||
|  | @ -208,18 +158,18 @@ public: | ||||||
| 	// to (this) received from the server "same" document.
 | 	// to (this) received from the server "same" document.
 | ||||||
| 	void collectLocalData(DocumentData *local); | 	void collectLocalData(DocumentData *local); | ||||||
| 
 | 
 | ||||||
| 	QString filename() const { | 	QString filename() const; | ||||||
| 		return _filename; | 	QString mimeString() const; | ||||||
| 	} | 	bool hasMimeType(QLatin1String mime) const; | ||||||
| 	QString mimeString() const { | 	void setMimeString(const QString &mime); | ||||||
| 		return _mimeString; | 
 | ||||||
| 	} | 	MediaKey mediaKey() const; | ||||||
| 	bool hasMimeType(QLatin1String mime) const { | 
 | ||||||
| 		return !_mimeString.compare(mime, Qt::CaseInsensitive); | 	static QString ComposeNameString( | ||||||
| 	} | 		const QString &filename, | ||||||
| 	void setMimeString(const QString &mime) { | 		const QString &songTitle, | ||||||
| 		_mimeString = mime; | 		const QString &songPerformer); | ||||||
| 	} | 	QString composeNameString() const; | ||||||
| 
 | 
 | ||||||
| 	~DocumentData(); | 	~DocumentData(); | ||||||
| 
 | 
 | ||||||
|  | @ -234,44 +184,12 @@ public: | ||||||
| 
 | 
 | ||||||
| 	std::unique_ptr<Data::UploadState> uploadingData; | 	std::unique_ptr<Data::UploadState> uploadingData; | ||||||
| 
 | 
 | ||||||
| 	int32 md5[8]; |  | ||||||
| 
 |  | ||||||
| 	MediaKey mediaKey() const { |  | ||||||
| 		return ::mediaKey(locationType(), _dc, id, _version); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	static QString ComposeNameString( |  | ||||||
| 		const QString &filename, |  | ||||||
| 		const QString &songTitle, |  | ||||||
| 		const QString &songPerformer); |  | ||||||
| 	QString composeNameString() const { |  | ||||||
| 		if (auto songData = song()) { |  | ||||||
| 			return ComposeNameString( |  | ||||||
| 				_filename, |  | ||||||
| 				songData->title, |  | ||||||
| 				songData->performer); |  | ||||||
| 		} |  | ||||||
| 		return ComposeNameString(_filename, QString(), QString()); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
| 	DocumentData( |  | ||||||
| 		DocumentId id, |  | ||||||
| 		int32 dc, |  | ||||||
| 		uint64 accessHash, |  | ||||||
| 		int32 version, |  | ||||||
| 		const QString &url, |  | ||||||
| 		const QVector<MTPDocumentAttribute> &attributes); |  | ||||||
| 
 |  | ||||||
| 	friend class Serialize::Document; | 	friend class Serialize::Document; | ||||||
| 
 | 
 | ||||||
| 	LocationType locationType() const { | 	LocationType locationType() const; | ||||||
| 		return isVoiceMessage() | 
 | ||||||
| 			? AudioFileLocation | 	void destroyLoaderDelayed(mtpFileLoader *newValue = nullptr) const; | ||||||
| 			: isVideoFile() |  | ||||||
| 				? VideoFileLocation |  | ||||||
| 				: DocumentFileLocation; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	// Two types of location: from MTProto by dc+access+version or from web by url
 | 	// Two types of location: from MTProto by dc+access+version or from web by url
 | ||||||
| 	int32 _dc = 0; | 	int32 _dc = 0; | ||||||
|  | @ -281,6 +199,8 @@ private: | ||||||
| 	QString _filename; | 	QString _filename; | ||||||
| 	QString _mimeString; | 	QString _mimeString; | ||||||
| 
 | 
 | ||||||
|  | 	not_null<AuthSession*> _session; | ||||||
|  | 
 | ||||||
| 	FileLocation _location; | 	FileLocation _location; | ||||||
| 	QByteArray _data; | 	QByteArray _data; | ||||||
| 	std::unique_ptr<DocumentAdditionalData> _additional; | 	std::unique_ptr<DocumentAdditionalData> _additional; | ||||||
|  | @ -290,9 +210,6 @@ private: | ||||||
| 	FullMsgId _actionOnLoadMsgId; | 	FullMsgId _actionOnLoadMsgId; | ||||||
| 	mutable FileLoader *_loader = nullptr; | 	mutable FileLoader *_loader = nullptr; | ||||||
| 
 | 
 | ||||||
| 	void destroyLoaderDelayed( |  | ||||||
| 		mtpFileLoader *newValue = nullptr) const; |  | ||||||
| 
 |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); | VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit); | ||||||
|  |  | ||||||
|  | @ -699,7 +699,9 @@ void Session::photoApplyFields( | ||||||
| not_null<DocumentData*> Session::document(DocumentId id) { | not_null<DocumentData*> Session::document(DocumentId id) { | ||||||
| 	auto i = _documents.find(id); | 	auto i = _documents.find(id); | ||||||
| 	if (i == _documents.cend()) { | 	if (i == _documents.cend()) { | ||||||
| 		i = _documents.emplace(id, DocumentData::create(id)).first; | 		i = _documents.emplace( | ||||||
|  | 			id, | ||||||
|  | 			std::make_unique<DocumentData>(id, _session)).first; | ||||||
| 	} | 	} | ||||||
| 	return i->second.get(); | 	return i->second.get(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1004,7 +1004,7 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { | ||||||
| 					if (media->type() == MediaTypeSticker) { | 					if (media->type() == MediaTypeSticker) { | ||||||
| 						if (const auto document = media->getDocument()) { | 						if (const auto document = media->getDocument()) { | ||||||
| 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | ||||||
| 								_menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | 								_menu->addAction(lang(document->isStickerSetInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | ||||||
| 									showStickerPackInfo(document); | 									showStickerPackInfo(document); | ||||||
| 								}); | 								}); | ||||||
| 							} | 							} | ||||||
|  |  | ||||||
|  | @ -1517,7 +1517,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { | ||||||
| 					if (media->type() == MediaTypeSticker) { | 					if (media->type() == MediaTypeSticker) { | ||||||
| 						if (auto document = media->getDocument()) { | 						if (auto document = media->getDocument()) { | ||||||
| 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | ||||||
| 								_menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | 								_menu->addAction(lang(document->isStickerSetInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | ||||||
| 									showStickerPackInfo(document); | 									showStickerPackInfo(document); | ||||||
| 								}); | 								}); | ||||||
| 								_menu->addAction(lang(Stickers::IsFaved(document) ? lng_faved_stickers_remove : lng_faved_stickers_add), [=] { | 								_menu->addAction(lang(Stickers::IsFaved(document) ? lng_faved_stickers_remove : lng_faved_stickers_add), [=] { | ||||||
|  |  | ||||||
|  | @ -204,7 +204,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu( | ||||||
| 					if (media->type() == MediaTypeSticker) { | 					if (media->type() == MediaTypeSticker) { | ||||||
| 						if (auto document = media->getDocument()) { | 						if (auto document = media->getDocument()) { | ||||||
| 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | 							if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) { | ||||||
| 								result->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | 								result->addAction(lang(document->isStickerSetInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] { | ||||||
| 									ShowStickerPackInfo(document); | 									ShowStickerPackInfo(document); | ||||||
| 								}); | 								}); | ||||||
| 							} | 							} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston