2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Save and load sticker set thumbnails.

This commit is contained in:
John Preston
2019-03-22 13:13:39 +04:00
parent eb1825defd
commit 386600baf9
6 changed files with 287 additions and 282 deletions

View File

@@ -60,6 +60,10 @@ constexpr auto kSinglePeerTypeChannel = qint32(3);
constexpr auto kSinglePeerTypeSelf = qint32(4);
constexpr auto kSinglePeerTypeEmpty = qint32(0);
constexpr auto kStickersVersionTag = quint32(-1);
constexpr auto kStickersSerializeVersion = 1;
constexpr auto kMaxSavedStickerSetsCount = 1000;
using Database = Storage::Cache::Database;
using FileKey = quint64;
@@ -3339,55 +3343,43 @@ void cancelTask(TaskId id) {
}
void _writeStickerSet(QDataStream &stream, const Stickers::Set &set) {
bool notLoaded = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded);
if (notLoaded) {
const auto writeInfo = [&](int count) {
stream
<< quint64(set.id)
<< quint64(set.access)
<< set.title
<< set.shortName
<< qint32(-set.count)
<< qint32(count)
<< qint32(set.hash)
<< qint32(set.flags);
if (AppVersion > 1002008) {
stream << qint32(set.installDate);
}
<< qint32(set.flags)
<< qint32(set.installDate);
Serialize::writeStorageImageLocation(
stream,
set.thumbnail ? set.thumbnail->location() : StorageImageLocation());
};
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
writeInfo(-set.count);
return;
} else if (set.stickers.isEmpty()) {
return;
} else {
if (set.stickers.isEmpty()) return;
}
stream
<< quint64(set.id)
<< quint64(set.access)
<< set.title
<< set.shortName
<< qint32(set.stickers.size())
<< qint32(set.hash)
<< qint32(set.flags);
if (AppVersion > 1002008) {
stream << qint32(set.installDate);
writeInfo(set.stickers.size());
for (const auto &sticker : set.stickers) {
Serialize::Document::writeToStream(stream, sticker);
}
for (auto j = set.stickers.cbegin(), e = set.stickers.cend(); j != e; ++j) {
Serialize::Document::writeToStream(stream, *j);
}
if (AppVersion > 1002008) {
stream << qint32(set.dates.size());
if (!set.dates.empty()) {
Assert(set.dates.size() == set.stickers.size());
for (const auto date : set.dates) {
stream << qint32(date);
}
stream << qint32(set.dates.size());
if (!set.dates.empty()) {
Assert(set.dates.size() == set.stickers.size());
for (const auto date : set.dates) {
stream << qint32(date);
}
}
if (AppVersion > 9018) {
stream << qint32(set.emoji.size());
for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
stream << j.key()->id() << qint32(j->size());
for (int32 k = 0, l = j->size(); k < l; ++k) {
stream << quint64(j->at(k)->id);
}
stream << qint32(set.emoji.size());
for (auto j = set.emoji.cbegin(), e = set.emoji.cend(); j != e; ++j) {
stream << j.key()->id() << qint32(j->size());
for (const auto sticker : *j) {
stream << quint64(sticker->id);
}
}
}
@@ -3415,9 +3407,11 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
_writeMap();
return;
}
// versionTag + version + count
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(qint32);
int32 setsCount = 0;
QByteArray hashToWrite;
quint32 size = sizeof(quint32) + Serialize::bytearraySize(hashToWrite);
for (const auto &set : sets) {
auto result = checkSet(set);
if (result == StickerSetCheckResult::Abort) {
@@ -3427,12 +3421,23 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
}
// id + access + title + shortName + stickersCount + hash + flags + installDate
size += sizeof(quint64) * 2 + Serialize::stringSize(set.title) + Serialize::stringSize(set.shortName) + sizeof(quint32) + sizeof(qint32) * 3;
for (const auto sticker : std::as_const(set.stickers)) {
size += sizeof(quint64) * 2
+ Serialize::stringSize(set.title)
+ Serialize::stringSize(set.shortName)
+ sizeof(qint32) * 4
+ Serialize::storageImageLocationSize(set.thumbnail
? set.thumbnail->location()
: StorageImageLocation());
if (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) {
continue;
}
for (const auto sticker : set.stickers) {
sticker->refreshStickerThumbFileReference();
size += Serialize::Document::sizeInStream(sticker);
}
size += sizeof(qint32); // dates count
size += sizeof(qint32); // datesCount
if (!set.dates.empty()) {
Assert(set.stickers.size() == set.dates.size());
size += set.dates.size() * sizeof(qint32);
@@ -3462,8 +3467,11 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
_writeMap(WriteMapWhen::Fast);
}
EncryptedDescriptor data(size);
data.stream << quint32(setsCount) << hashToWrite;
for_const (auto &set, sets) {
data.stream
<< quint32(kStickersVersionTag)
<< qint32(kStickersSerializeVersion)
<< qint32(setsCount);
for (const auto &set : sets) {
auto result = checkSet(set);
if (result == StickerSetCheckResult::Abort) {
return;
@@ -3487,54 +3495,60 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
return;
}
bool readingInstalled = (readingFlags == MTPDstickerSet::Flag::f_installed_date);
const auto failed = [&] {
clearKey(stickersKey);
stickersKey = 0;
};
auto &sets = Auth().data().stickerSetsRef();
if (outOrder) outOrder->clear();
quint32 cnt;
QByteArray hash;
stickers.stream >> cnt >> hash; // ignore hash, it is counted
if (readingInstalled && stickers.version < 8019) { // bad data in old caches
cnt += 2; // try to read at least something
quint32 versionTag = 0;
qint32 version = 0;
stickers.stream >> versionTag >> version;
if (versionTag != kStickersVersionTag
|| version <= 0
|| version > kStickersSerializeVersion) {
// Old data, without sticker set thumbnails.
return failed();
}
for (uint32 i = 0; i < cnt; ++i) {
qint32 count = 0;
stickers.stream >> count;
if (!_checkStreamStatus(stickers.stream)
|| (count < 0)
|| (count > kMaxSavedStickerSetsCount)) {
return failed();
}
for (auto i = 0; i != count; ++i) {
quint64 setId = 0, setAccess = 0;
QString setTitle, setShortName;
qint32 scnt = 0;
auto setInstallDate = qint32(0);
qint32 setInstallDate = 0;
qint32 setHash = 0;
MTPDstickerSet::Flags setFlags = 0;
qint32 setFlagsValue = 0;
StorageImageLocation setThumbnail;
stickers.stream
>> setId
>> setAccess
>> setTitle
>> setShortName
>> scnt;
qint32 setHash = 0;
MTPDstickerSet::Flags setFlags = 0;
if (stickers.version > 8033) {
qint32 setFlagsValue = 0;
stickers.stream >> setHash >> setFlagsValue;
setFlags = MTPDstickerSet::Flags::from_raw(setFlagsValue);
if (setFlags & MTPDstickerSet_ClientFlag::f_not_loaded__old) {
setFlags &= ~MTPDstickerSet_ClientFlag::f_not_loaded__old;
setFlags |= MTPDstickerSet_ClientFlag::f_not_loaded;
}
}
if (stickers.version > 1002008) {
stickers.stream >> setInstallDate;
}
if (readingInstalled && stickers.version < 9061) {
setFlags |= MTPDstickerSet::Flag::f_installed_date;
>> scnt
>> setHash
>> setFlagsValue
>> setInstallDate;
setThumbnail = Serialize::readStorageImageLocation(
stickers.version,
stickers.stream);
if (!_checkStreamStatus(stickers.stream)) {
return failed();
}
setFlags = MTPDstickerSet::Flags::from_raw(setFlagsValue);
if (setId == Stickers::DefaultSetId) {
setTitle = lang(lng_stickers_default_set);
setFlags |= MTPDstickerSet::Flag::f_official | MTPDstickerSet_ClientFlag::f_special;
if (readingInstalled && outOrder && stickers.version < 9061) {
outOrder->push_front(setId);
}
} else if (setId == Stickers::CustomSetId) {
setTitle = qsl("Custom stickers");
setFlags |= MTPDstickerSet_ClientFlag::f_special;
@@ -3544,11 +3558,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
} else if (setId == Stickers::FavedSetId) {
setTitle = Lang::Hard::FavedSetTitle();
setFlags |= MTPDstickerSet_ClientFlag::f_special;
} else if (setId) {
if (readingInstalled && outOrder && stickers.version < 9061) {
outOrder->push_back(setId);
}
} else {
} else if (!setId) {
continue;
}
@@ -3564,33 +3574,37 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
0,
setHash,
MTPDstickerSet::Flags(setFlags),
setInstallDate));
setInstallDate,
setThumbnail.isNull() ? ImagePtr() : Images::Create(setThumbnail)));
}
auto &set = it.value();
auto inputSet = MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
const auto fillStickers = set.stickers.isEmpty();
if (scnt < 0) { // disabled not loaded set
if (!set.count || set.stickers.isEmpty()) {
if (!set.count || fillStickers) {
set.count = -scnt;
}
continue;
}
bool fillStickers = set.stickers.isEmpty();
if (fillStickers) {
set.stickers.reserve(scnt);
set.count = 0;
}
Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName);
OrderedSet<DocumentId> read;
base::flat_set<DocumentId> read;
for (int32 j = 0; j < scnt; ++j) {
auto document = Serialize::Document::readStickerFromStream(stickers.version, stickers.stream, info);
if (!document || !document->sticker()) continue;
if (read.contains(document->id)) continue;
read.insert(document->id);
if (!_checkStreamStatus(stickers.stream)) {
return failed();
} else if (!document
|| !document->sticker()
|| read.contains(document->id)) {
continue;
}
read.emplace(document->id);
if (fillStickers) {
set.stickers.push_back(document);
if (!(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
@@ -3602,64 +3616,71 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
}
}
if (stickers.version > 1002008) {
auto datesCount = qint32(0);
stickers.stream >> datesCount;
if (datesCount > 0) {
if (datesCount != scnt) {
// Bad file.
return;
}
qint32 datesCount = 0;
stickers.stream >> datesCount;
if (datesCount > 0) {
if (datesCount != scnt) {
return failed();
}
const auto fillDates = (set.id == Stickers::CloudRecentSetId)
&& (set.stickers.size() == datesCount);
if (fillDates) {
set.dates.clear();
set.dates.reserve(datesCount);
for (auto i = 0; i != datesCount; ++i) {
auto date = qint32();
stickers.stream >> date;
if (set.id == Stickers::CloudRecentSetId) {
set.dates.push_back(TimeId(date));
}
}
for (auto i = 0; i != datesCount; ++i) {
qint32 date = 0;
stickers.stream >> date;
if (fillDates) {
set.dates.push_back(TimeId(date));
}
}
}
if (stickers.version > 9018) {
qint32 emojiCount;
stickers.stream >> emojiCount;
for (int32 j = 0; j < emojiCount; ++j) {
QString emojiString;
qint32 stickersCount;
stickers.stream >> emojiString >> stickersCount;
Stickers::Pack pack;
pack.reserve(stickersCount);
for (int32 k = 0; k < stickersCount; ++k) {
quint64 id;
stickers.stream >> id;
const auto doc = Auth().data().document(id);
if (!doc->sticker()) continue;
qint32 emojiCount = 0;
stickers.stream >> emojiCount;
if (!_checkStreamStatus(stickers.stream) || emojiCount < 0) {
return failed();
}
for (int32 j = 0; j < emojiCount; ++j) {
QString emojiString;
qint32 stickersCount;
stickers.stream >> emojiString >> stickersCount;
Stickers::Pack pack;
pack.reserve(stickersCount);
for (int32 k = 0; k < stickersCount; ++k) {
quint64 id;
stickers.stream >> id;
const auto doc = Auth().data().document(id);
if (!doc->sticker()) continue;
pack.push_back(doc);
}
if (fillStickers) {
if (auto emoji = Ui::Emoji::Find(emojiString)) {
emoji = emoji->original();
set.emoji.insert(emoji, pack);
}
pack.push_back(doc);
}
if (fillStickers) {
if (auto emoji = Ui::Emoji::Find(emojiString)) {
emoji = emoji->original();
set.emoji.insert(emoji, pack);
}
}
}
}
// Read orders of installed and featured stickers.
if (outOrder && stickers.version >= 9061) {
if (outOrder) {
stickers.stream >> *outOrder;
}
if (!_checkStreamStatus(stickers.stream)) {
return failed();
}
// Set flags that we dropped above from the order.
if (readingFlags && outOrder) {
for_const (auto setId, *outOrder) {
for (const auto setId : std::as_const(*outOrder)) {
auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags |= readingFlags;
if (readingInstalled && !it->installDate) {
if ((readingFlags == MTPDstickerSet::Flag::f_installed_date)
&& !it->installDate) {
it->installDate = kDefaultStickerInstallDate;
}
}
@@ -3770,7 +3791,8 @@ void importOldRecentStickers() {
(MTPDstickerSet::Flag::f_official
| MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate)).value();
kDefaultStickerInstallDate,
ImagePtr())).value();
auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(
Stickers::CustomSetId,
uint64(0),
@@ -3780,7 +3802,8 @@ void importOldRecentStickers() {
0, // hash
(MTPDstickerSet::Flag::f_installed_date
| MTPDstickerSet_ClientFlag::f_special),
kDefaultStickerInstallDate)).value();
kDefaultStickerInstallDate,
ImagePtr())).value();
QMap<uint64, bool> read;
while (!stickers.stream.atEnd()) {