mirror of https://github.com/procxx/kepka.git
				
				
				
			Add support for gzip-ed animated stickers.
This commit is contained in:
		
							parent
							
								
									973c3f8838
								
							
						
					
					
						commit
						4ab3c2dfcb
					
				|  | @ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| 
 | 
 | ||||||
| #include "zip.h" | #include "zip.h" | ||||||
| #include "unzip.h" | #include "unzip.h" | ||||||
|  | #include "logs.h" | ||||||
| 
 | 
 | ||||||
| #ifdef small | #ifdef small | ||||||
| #undef small | #undef small | ||||||
|  |  | ||||||
|  | @ -554,7 +554,8 @@ void DocumentData::setattributes( | ||||||
| 
 | 
 | ||||||
| void DocumentData::validateLottieSticker() { | void DocumentData::validateLottieSticker() { | ||||||
| 	if (type == FileDocument | 	if (type == FileDocument | ||||||
| 		&& (_filename == qstr("animation.json") | 		&& (_filename.endsWith(qstr(".tgs")) | ||||||
|  | 			|| _filename == qstr("animation.json") | ||||||
| 			|| ((_filename.size() == 9 || _filename.size() == 10) | 			|| ((_filename.size() == 9 || _filename.size() == 10) | ||||||
| 				&& _filename.endsWith(qstr(".json")) | 				&& _filename.endsWith(qstr(".json")) | ||||||
| 				&& QRegularExpression("^\\d+\\.json$").match(_filename).hasMatch()))) { | 				&& QRegularExpression("^\\d+\\.json$").match(_filename).hasMatch()))) { | ||||||
|  |  | ||||||
|  | @ -123,7 +123,9 @@ void HistorySticker::unloadLottie() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const { | void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const { | ||||||
| 	if (!_lottie && _data->filename().endsWith(qstr(".json"))) { | 	if (!_lottie | ||||||
|  | 		&& (_data->filename().endsWith(qstr(".tgs")) | ||||||
|  | 			|| _data->filename().endsWith(qstr(".json")))) { | ||||||
| 		if (_data->loaded()) { | 		if (_data->loaded()) { | ||||||
| 			const_cast<HistorySticker*>(this)->setupLottie(); | 			const_cast<HistorySticker*>(this)->setupLottie(); | ||||||
| 		} else { | 		} else { | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "rasterrenderer/rasterrenderer.h" | #include "rasterrenderer/rasterrenderer.h" | ||||||
| #include "json.h" | #include "json.h" | ||||||
| #include "base/algorithm.h" | #include "base/algorithm.h" | ||||||
|  | #include "zlib.h" | ||||||
| #include "logs.h" | #include "logs.h" | ||||||
| 
 | 
 | ||||||
| #include <QFile> | #include <QFile> | ||||||
|  | @ -18,16 +19,54 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include <crl/crl_on_main.h> | #include <crl/crl_on_main.h> | ||||||
| 
 | 
 | ||||||
| namespace Lottie { | namespace Lottie { | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | constexpr auto kMaxSize = 1024 * 1024; | ||||||
|  | 
 | ||||||
|  | QByteArray UnpackGzip(const QByteArray &bytes) { | ||||||
|  | 	z_stream stream; | ||||||
|  | 	stream.zalloc = nullptr; | ||||||
|  | 	stream.zfree = nullptr; | ||||||
|  | 	stream.opaque = nullptr; | ||||||
|  | 	stream.avail_in = 0; | ||||||
|  | 	stream.next_in = nullptr; | ||||||
|  | 	int res = inflateInit2(&stream, 16 + MAX_WBITS); | ||||||
|  | 	if (res != Z_OK) { | ||||||
|  | 		return bytes; | ||||||
|  | 	} | ||||||
|  | 	const auto guard = gsl::finally([&] { inflateEnd(&stream); }); | ||||||
|  | 
 | ||||||
|  | 	auto result = QByteArray(kMaxSize + 1, Qt::Uninitialized); | ||||||
|  | 	stream.avail_in = bytes.size(); | ||||||
|  | 	stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(bytes.data())); | ||||||
|  | 	stream.avail_out = 0; | ||||||
|  | 	while (!stream.avail_out) { | ||||||
|  | 		stream.avail_out = result.size(); | ||||||
|  | 		stream.next_out = reinterpret_cast<Bytef*>(result.data()); | ||||||
|  | 		int res = inflate(&stream, Z_NO_FLUSH); | ||||||
|  | 		if (res != Z_OK && res != Z_STREAM_END) { | ||||||
|  | 			return bytes; | ||||||
|  | 		} else if (!stream.avail_out) { | ||||||
|  | 			return bytes; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	result.resize(result.size() - stream.avail_out); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace
 | ||||||
| 
 | 
 | ||||||
| bool ValidateFile(const QString &path) { | bool ValidateFile(const QString &path) { | ||||||
| 	if (!path.endsWith(qstr(".json"), Qt::CaseInsensitive)) { | 	if (!path.endsWith(qstr(".json"), Qt::CaseInsensitive) | ||||||
|  | 		&& !path.endsWith(qstr(".tgs"), Qt::CaseInsensitive)) { | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::unique_ptr<Animation> FromFile(const QString &path) { | std::unique_ptr<Animation> FromFile(const QString &path) { | ||||||
| 	if (!path.endsWith(qstr(".json"), Qt::CaseInsensitive)) { | 	if (!path.endsWith(qstr(".json"), Qt::CaseInsensitive) | ||||||
|  | 		&& !path.endsWith(qstr(".tgs"), Qt::CaseInsensitive)) { | ||||||
| 		return nullptr; | 		return nullptr; | ||||||
| 	} | 	} | ||||||
| 	auto f = QFile(path); | 	auto f = QFile(path); | ||||||
|  | @ -50,11 +89,21 @@ Animation::Animation(QByteArray &&content) | ||||||
| 	const auto weak = base::make_weak(this); | 	const auto weak = base::make_weak(this); | ||||||
| 	crl::async([=, content = base::take(content)]() mutable { | 	crl::async([=, content = base::take(content)]() mutable { | ||||||
| 		const auto now = crl::now(); | 		const auto now = crl::now(); | ||||||
|  | 		content = UnpackGzip(content); | ||||||
|  | 		if (content.size() > kMaxSize) { | ||||||
|  | 			qWarning() | ||||||
|  | 				<< "Lottie Error: Too large file: " | ||||||
|  | 				<< content.size(); | ||||||
|  | 			crl::on_main(weak, [=] { | ||||||
|  | 				parseFailed(); | ||||||
|  | 			}); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		const auto document = JsonDocument(std::move(content)); | 		const auto document = JsonDocument(std::move(content)); | ||||||
| 		const auto parsed = crl::now(); | 		const auto parsed = crl::now(); | ||||||
| 		if (const auto error = document.error()) { | 		if (const auto error = document.error()) { | ||||||
| 			qWarning() | 			qWarning() | ||||||
| 				<< "Lottie Error: Parse failed with code " | 				<< "Lottie Error: Parse failed with code: " | ||||||
| 				<< error; | 				<< error; | ||||||
| 			crl::on_main(weak, [=] { | 			crl::on_main(weak, [=] { | ||||||
| 				parseFailed(); | 				parseFailed(); | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ | ||||||
|       '<(src_loc)', |       '<(src_loc)', | ||||||
|       '<(SHARED_INTERMEDIATE_DIR)', |       '<(SHARED_INTERMEDIATE_DIR)', | ||||||
|       '<(libs_loc)/range-v3/include', |       '<(libs_loc)/range-v3/include', | ||||||
|  |       '<(libs_loc)/zlib', | ||||||
|       '<(lottie_loc)', |       '<(lottie_loc)', | ||||||
|       '<(lottie_loc)/bodymovin', |       '<(lottie_loc)/bodymovin', | ||||||
|       '<(lottie_loc)/imports', |       '<(lottie_loc)/imports', | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue