mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
Encapsulated DocumentData location and serialization.
DocumentData now can point to mtproto or http file.
This commit is contained in:
parent
ff839bd978
commit
0894931fa1
16 changed files with 514 additions and 236 deletions
|
@ -1521,7 +1521,7 @@ namespace {
|
|||
DocumentData *document(const DocumentId &document) {
|
||||
DocumentsData::const_iterator i = ::documentsData.constFind(document);
|
||||
if (i == ::documentsData.cend()) {
|
||||
i = ::documentsData.insert(document, new DocumentData(document));
|
||||
i = ::documentsData.insert(document, DocumentData::create(document));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
@ -1529,45 +1529,44 @@ namespace {
|
|||
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) {
|
||||
bool sentSticker = false;
|
||||
if (convert) {
|
||||
MediaKey oldKey = convert->mediaKey();
|
||||
if (convert->id != document) {
|
||||
DocumentsData::iterator i = ::documentsData.find(convert->id);
|
||||
if (i != ::documentsData.cend() && i.value() == convert) {
|
||||
::documentsData.erase(i);
|
||||
}
|
||||
|
||||
// inline bot sent gifs caching
|
||||
if (!convert->voice() && !convert->isVideo()) {
|
||||
Local::copyStickerImage(mediaKey(DocumentFileLocation, convert->dc, convert->id), mediaKey(DocumentFileLocation, dc, document));
|
||||
}
|
||||
|
||||
convert->id = document;
|
||||
convert->status = FileReady;
|
||||
sentSticker = (convert->sticker() != 0);
|
||||
}
|
||||
if (date) {
|
||||
convert->access = access;
|
||||
convert->date = date;
|
||||
convert->setattributes(attributes);
|
||||
convert->setRemoteLocation(dc, access);
|
||||
convert->date = date;
|
||||
convert->mime = mime;
|
||||
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) {
|
||||
updateImage(convert->thumb, thumb);
|
||||
}
|
||||
convert->dc = dc;
|
||||
convert->size = size;
|
||||
convert->recountIsImage();
|
||||
if (convert->sticker() && convert->sticker()->loc.isNull() && !thumbLocation.isNull()) {
|
||||
convert->sticker()->loc = thumbLocation;
|
||||
}
|
||||
|
||||
MediaKey newKey = convert->mediaKey();
|
||||
if (newKey != oldKey) {
|
||||
if (convert->voice()) {
|
||||
Local::copyAudio(oldKey, newKey);
|
||||
} else if (convert->sticker() || convert->isAnimation()) {
|
||||
Local::copyStickerImage(oldKey, newKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cSavedGifs().indexOf(convert) >= 0) { // id changed
|
||||
Local::writeSavedGifs();
|
||||
}
|
||||
|
||||
const FileLocation &loc(convert->location(true));
|
||||
if (!loc.isEmpty()) {
|
||||
Local::writeFileLocation(convert->mediaKey(), loc);
|
||||
}
|
||||
}
|
||||
DocumentsData::const_iterator i = ::documentsData.constFind(document);
|
||||
DocumentData *result;
|
||||
|
@ -1575,7 +1574,11 @@ namespace {
|
|||
if (convert) {
|
||||
result = convert;
|
||||
} else {
|
||||
result = new DocumentData(document, access, date, attributes, mime, thumb, dc, size);
|
||||
result = DocumentData::create(document, dc, access, attributes);
|
||||
result->date = date;
|
||||
result->mime = mime;
|
||||
result->thumb = thumb;
|
||||
result->size = size;
|
||||
result->recountIsImage();
|
||||
if (result->sticker()) {
|
||||
result->sticker()->loc = thumbLocation;
|
||||
|
@ -1585,14 +1588,15 @@ namespace {
|
|||
} else {
|
||||
result = i.value();
|
||||
if (result != convert && date) {
|
||||
result->access = access;
|
||||
result->date = date;
|
||||
result->setattributes(attributes);
|
||||
if (!result->isValid()) {
|
||||
result->setRemoteLocation(dc, access);
|
||||
}
|
||||
result->date = date;
|
||||
result->mime = mime;
|
||||
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) {
|
||||
result->thumb = thumb;
|
||||
}
|
||||
result->dc = dc;
|
||||
result->size = size;
|
||||
result->recountIsImage();
|
||||
if (result->sticker() && result->sticker()->loc.isNull() && !thumbLocation.isNull()) {
|
||||
|
|
|
@ -4606,7 +4606,7 @@ void HistoryDocument::getState(ClickHandlerPtr &lnk, HistoryCursorState &state,
|
|||
}
|
||||
height -= captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
||||
}
|
||||
if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->access) {
|
||||
if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->isValid()) {
|
||||
lnk = _openl;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3422,7 +3422,10 @@ void HistoryWidget::savedGifsGot(const MTPmessages_SavedGifs &gifs) {
|
|||
|
||||
void HistoryWidget::saveGif(DocumentData *doc) {
|
||||
if (doc->isGifv() && cSavedGifs().indexOf(doc) != 0) {
|
||||
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_bool(false)), rpcDone(&HistoryWidget::saveGifDone, doc));
|
||||
MTPInputDocument mtpInput = doc->mtpInput();
|
||||
if (mtpInput.type() != mtpc_inputDocumentEmpty) {
|
||||
MTP::send(MTPmessages_SaveGif(mtpInput, MTP_bool(false)), rpcDone(&HistoryWidget::saveGifDone, doc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7027,7 +7030,14 @@ void HistoryWidget::ReplyEditMessageDataCallback::call(ChannelData *channel, Msg
|
|||
}
|
||||
|
||||
void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &caption) {
|
||||
if (!_history || !doc || !canSendMessages(_peer)) return;
|
||||
if (!_history || !doc || !canSendMessages(_peer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MTPInputDocument mtpInput = doc->mtpInput();
|
||||
if (mtpInput.type() == mtpc_inputDocumentEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
App::main()->readServerHistory(_history, false);
|
||||
fastShowAtEnd(_history);
|
||||
|
@ -7060,7 +7070,7 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
|
|||
}
|
||||
_history->addNewDocument(newId.msg, flags, 0, replyToId(), date(MTP_int(unixtime())), showFromName ? MTP::authedId() : 0, doc, caption, MTPnullMarkup);
|
||||
|
||||
_history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaDocument(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_string(caption)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
|
||||
_history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(sendFlags), _peer->input, MTP_int(replyToId()), MTP_inputMediaDocument(mtpInput, MTP_string(caption)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
|
||||
App::main()->finishForwarding(_history, _broadcast.checked(), _silent.checked());
|
||||
cancelReply(lastKeyboardUsed);
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ void DeleteSavedGifClickHandler::onClickImpl() const {
|
|||
cRefSavedGifs().remove(index);
|
||||
Local::writeSavedGifs();
|
||||
|
||||
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(_data->id), MTP_long(_data->access)), MTP_bool(true)));
|
||||
MTP::send(MTPmessages_SaveGif(_data->mtpInput(), MTP_bool(true)));
|
||||
}
|
||||
if (App::main()) emit App::main()->savedGifsUpdated();
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ UniquePointer<Result> Result::create(uint64 queryId, const MTPBotInlineResult &m
|
|||
message = &r.vsend_message;
|
||||
} break;
|
||||
}
|
||||
bool badAttachment = (result->_photo && !result->_photo->access) || (result->_document && !result->_document->access);
|
||||
bool badAttachment = (result->_photo && !result->_photo->access) || (result->_document && !result->_document->isValid());
|
||||
|
||||
if (!message) {
|
||||
return UniquePointer<Result>();
|
||||
|
|
|
@ -801,7 +801,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
|
|||
bool selected = (selection == FullSelection);
|
||||
|
||||
_data->automaticLoad(_parent);
|
||||
bool loaded = _data->loaded() || Local::willStickerImageLoad(mediaKey(DocumentFileLocation, _data->dc, _data->id)), displayLoading = _data->displayLoading();
|
||||
bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()), displayLoading = _data->displayLoading();
|
||||
|
||||
if (displayLoading) {
|
||||
ensureRadial();
|
||||
|
@ -973,7 +973,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
|
|||
}
|
||||
|
||||
void LayoutOverviewDocument::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
|
||||
bool loaded = _data->loaded() || Local::willStickerImageLoad(mediaKey(DocumentFileLocation, _data->dc, _data->id));
|
||||
bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey());
|
||||
|
||||
bool showPause = updateStatusText();
|
||||
|
||||
|
@ -1014,7 +1014,7 @@ void LayoutOverviewDocument::getState(ClickHandlerPtr &link, HistoryCursorState
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (!_data->loading() && _data->access) {
|
||||
if (!_data->loading() && _data->isValid()) {
|
||||
if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(x, y)) {
|
||||
link = _namel;
|
||||
return;
|
||||
|
|
|
@ -19,22 +19,18 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "serialize/serialize_document.h"
|
||||
#include "serialize/serialize_common.h"
|
||||
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
#include "lang.h"
|
||||
|
||||
namespace {
|
||||
enum StickerSetType {
|
||||
StickerSetTypeEmpty = 0,
|
||||
StickerSetTypeID = 1,
|
||||
StickerSetTypeShortName = 2,
|
||||
};
|
||||
|
||||
typedef quint64 FileKey;
|
||||
|
||||
static const char tdfMagic[] = { 'T', 'D', 'F', '$' };
|
||||
|
@ -150,10 +146,6 @@ namespace {
|
|||
return (sizeof(qint64) + sizeof(quint32) + sizeof(qint8));
|
||||
}
|
||||
|
||||
uint32 _stringSize(const QString &str) {
|
||||
return sizeof(quint32) + str.size() * sizeof(ushort);
|
||||
}
|
||||
|
||||
uint32 _bytearraySize(const QByteArray &arr) {
|
||||
return sizeof(quint32) + arr.size();
|
||||
}
|
||||
|
@ -691,7 +683,7 @@ namespace {
|
|||
quint32 size = 0;
|
||||
for (FileLocations::const_iterator i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
|
||||
// location + type + namelen + name
|
||||
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name());
|
||||
size += sizeof(quint64) * 2 + sizeof(quint32) + Serialize::stringSize(i.value().name());
|
||||
if (AppVersion > 9013) {
|
||||
// bookmark
|
||||
size += _bytearraySize(i.value().bookmark());
|
||||
|
@ -701,7 +693,7 @@ namespace {
|
|||
}
|
||||
|
||||
//end mark
|
||||
size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString());
|
||||
size += sizeof(quint64) * 2 + sizeof(quint32) + Serialize::stringSize(QString());
|
||||
if (AppVersion > 9013) {
|
||||
size += _bytearraySize(QByteArray());
|
||||
}
|
||||
|
@ -716,7 +708,7 @@ namespace {
|
|||
size += sizeof(quint32); // web files count
|
||||
for (WebFilesMap::const_iterator i = _webFilesMap.cbegin(), e = _webFilesMap.cend(); i != e; ++i) {
|
||||
// url + filekey + size
|
||||
size += _stringSize(i.key()) + sizeof(quint64) + sizeof(qint32);
|
||||
size += Serialize::stringSize(i.key()) + sizeof(quint64) + sizeof(qint32);
|
||||
}
|
||||
|
||||
EncryptedDescriptor data(size);
|
||||
|
@ -1580,11 +1572,11 @@ namespace {
|
|||
}
|
||||
|
||||
uint32 size = 16 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath()) + _bytearraySize(cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
|
||||
size += sizeof(quint32) + Serialize::stringSize(cAskDownloadPath() ? QString() : cDownloadPath()) + _bytearraySize(cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + _stringSize(cDialogLastPath());
|
||||
size += sizeof(quint32) + Serialize::stringSize(cDialogLastPath());
|
||||
size += sizeof(quint32) + 3 * sizeof(qint32);
|
||||
if (!Global::HiddenPinnedMessages().isEmpty()) {
|
||||
size += sizeof(quint32) + sizeof(qint32) + Global::HiddenPinnedMessages().size() * (sizeof(PeerId) + sizeof(MsgId));
|
||||
|
@ -2209,14 +2201,14 @@ namespace Local {
|
|||
quint32 size = 12 * (sizeof(quint32) + sizeof(qint32));
|
||||
for (auto i = dcOpts.cbegin(), e = dcOpts.cend(); i != e; ++i) {
|
||||
size += sizeof(quint32) + sizeof(quint32) + sizeof(quint32);
|
||||
size += sizeof(quint32) + _stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
|
||||
size += sizeof(quint32) + Serialize::stringSize(QString::fromUtf8(i->ip.data(), i->ip.size()));
|
||||
}
|
||||
size += sizeof(quint32) + _stringSize(cLangFile());
|
||||
size += sizeof(quint32) + Serialize::stringSize(cLangFile());
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32);
|
||||
if (cConnectionType() == dbictHttpProxy || cConnectionType() == dbictTcpProxy) {
|
||||
const ConnectionProxy &proxy(cConnectionProxy());
|
||||
size += _stringSize(proxy.host) + sizeof(qint32) + _stringSize(proxy.user) + _stringSize(proxy.password);
|
||||
size += Serialize::stringSize(proxy.host) + sizeof(qint32) + Serialize::stringSize(proxy.user) + Serialize::stringSize(proxy.password);
|
||||
}
|
||||
|
||||
size += sizeof(quint32) + sizeof(qint32) * 6;
|
||||
|
@ -2347,7 +2339,7 @@ namespace Local {
|
|||
_writeMap(WriteMapFast);
|
||||
}
|
||||
|
||||
EncryptedDescriptor data(sizeof(quint64) + _stringSize(msgDraft.text) + 2 * sizeof(qint32) + _stringSize(editDraft.text) + 2 * sizeof(qint32));
|
||||
EncryptedDescriptor data(sizeof(quint64) + Serialize::stringSize(msgDraft.text) + 2 * sizeof(qint32) + Serialize::stringSize(editDraft.text) + 2 * sizeof(qint32));
|
||||
data.stream << quint64(peer);
|
||||
data.stream << msgDraft.text << qint32(msgDraft.msgId) << qint32(msgDraft.previewCancelled ? 1 : 0);
|
||||
data.stream << editDraft.text << qint32(editDraft.msgId) << qint32(editDraft.previewCancelled ? 1 : 0);
|
||||
|
@ -2734,7 +2726,7 @@ namespace Local {
|
|||
type = StorageFilePartial;
|
||||
}
|
||||
void clearInMap() {
|
||||
StorageMap::iterator j = _stickerImagesMap.find(_location);
|
||||
auto j = _stickerImagesMap.find(_location);
|
||||
if (j != _stickerImagesMap.cend() && j->first == _key) {
|
||||
clearKey(j.value().first, UserPath);
|
||||
_storageStickersSize -= j.value().second;
|
||||
|
@ -2744,7 +2736,7 @@ namespace Local {
|
|||
};
|
||||
|
||||
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader) {
|
||||
StorageMap::const_iterator j = _stickerImagesMap.constFind(location);
|
||||
auto j = _stickerImagesMap.constFind(location);
|
||||
if (j == _stickerImagesMap.cend() || !_localLoader) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -2756,7 +2748,7 @@ namespace Local {
|
|||
}
|
||||
|
||||
void copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation) {
|
||||
StorageMap::const_iterator i = _stickerImagesMap.constFind(oldLocation);
|
||||
auto i = _stickerImagesMap.constFind(oldLocation);
|
||||
if (i != _stickerImagesMap.cend()) {
|
||||
_stickerImagesMap.insert(newLocation, i.value());
|
||||
_mapChanged = true;
|
||||
|
@ -2806,7 +2798,7 @@ namespace Local {
|
|||
type = StorageFilePartial;
|
||||
}
|
||||
void clearInMap() {
|
||||
StorageMap::iterator j = _audiosMap.find(_location);
|
||||
auto j = _audiosMap.find(_location);
|
||||
if (j != _audiosMap.cend() && j->first == _key) {
|
||||
clearKey(j.value().first, UserPath);
|
||||
_storageAudiosSize -= j.value().second;
|
||||
|
@ -2816,13 +2808,22 @@ namespace Local {
|
|||
};
|
||||
|
||||
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) {
|
||||
StorageMap::const_iterator j = _audiosMap.constFind(location);
|
||||
auto j = _audiosMap.constFind(location);
|
||||
if (j == _audiosMap.cend() || !_localLoader) {
|
||||
return 0;
|
||||
}
|
||||
return _localLoader->addTask(new AudioLoadTask(j->first, location, loader));
|
||||
}
|
||||
|
||||
void copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation) {
|
||||
auto i = _audiosMap.constFind(oldLocation);
|
||||
if (i != _audiosMap.cend()) {
|
||||
_audiosMap.insert(newLocation, i.value());
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
}
|
||||
}
|
||||
|
||||
int32 hasAudios() {
|
||||
return _audiosMap.size();
|
||||
}
|
||||
|
@ -2833,7 +2834,7 @@ namespace Local {
|
|||
|
||||
qint32 _storageWebFileSize(const QString &url, qint32 rawlen) {
|
||||
// fulllen + url + len + data
|
||||
qint32 result = sizeof(uint32) + _stringSize(url) + sizeof(quint32) + rawlen;
|
||||
qint32 result = sizeof(uint32) + Serialize::stringSize(url) + sizeof(quint32) + rawlen;
|
||||
if (result & 0x0F) result += 0x10 - (result & 0x0F);
|
||||
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
|
||||
return result;
|
||||
|
@ -2851,7 +2852,7 @@ namespace Local {
|
|||
} else if (!overwrite) {
|
||||
return;
|
||||
}
|
||||
EncryptedDescriptor data(_stringSize(url) + sizeof(quint32) + sizeof(quint32) + content.size());
|
||||
EncryptedDescriptor data(Serialize::stringSize(url) + sizeof(quint32) + sizeof(quint32) + content.size());
|
||||
data.stream << url << content;
|
||||
FileWriteDescriptor file(i.value().first, UserPath);
|
||||
file.writeEncrypted(data);
|
||||
|
@ -3012,23 +3013,6 @@ namespace Local {
|
|||
}
|
||||
}
|
||||
|
||||
void _writeStorageImageLocation(QDataStream &stream, const StorageImageLocation &loc) {
|
||||
stream << qint32(loc.width()) << qint32(loc.height());
|
||||
stream << qint32(loc.dc()) << quint64(loc.volume()) << qint32(loc.local()) << quint64(loc.secret());
|
||||
}
|
||||
|
||||
uint32 _storageImageLocationSize() {
|
||||
// width + height + dc + volume + local + secret
|
||||
return sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint64) + sizeof(qint32) + sizeof(quint64);
|
||||
}
|
||||
|
||||
StorageImageLocation _readStorageImageLocation(FileReadDescriptor &from) {
|
||||
qint32 thumbWidth, thumbHeight, thumbDc, thumbLocal;
|
||||
quint64 thumbVolume, thumbSecret;
|
||||
from.stream >> thumbWidth >> thumbHeight >> thumbDc >> thumbVolume >> thumbLocal >> thumbSecret;
|
||||
return StorageImageLocation(thumbWidth, thumbHeight, thumbDc, thumbVolume, thumbLocal, thumbSecret);
|
||||
}
|
||||
|
||||
void _writeStickerSet(QDataStream &stream, uint64 setId) {
|
||||
auto it = Global::StickerSets().constFind(setId);
|
||||
if (it == Global::StickerSets().cend()) return;
|
||||
|
@ -3043,21 +3027,7 @@ namespace Local {
|
|||
|
||||
stream << quint64(it->id) << quint64(it->access) << it->title << it->shortName << qint32(it->stickers.size()) << qint32(it->hash) << qint32(it->flags);
|
||||
for (StickerPack::const_iterator j = it->stickers.cbegin(), e = it->stickers.cend(); j != e; ++j) {
|
||||
DocumentData *doc = *j;
|
||||
stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << doc->sticker()->alt;
|
||||
switch (doc->sticker()->set.type()) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
stream << qint32(StickerSetTypeID);
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
stream << qint32(StickerSetTypeShortName);
|
||||
} break;
|
||||
case mtpc_inputStickerSetEmpty:
|
||||
default: {
|
||||
stream << qint32(StickerSetTypeEmpty);
|
||||
} break;
|
||||
}
|
||||
_writeStorageImageLocation(stream, doc->sticker()->loc);
|
||||
Serialize::Document::writeToStream(stream, *j);
|
||||
}
|
||||
|
||||
if (AppVersion > 9018) {
|
||||
|
@ -3097,21 +3067,15 @@ namespace Local {
|
|||
}
|
||||
|
||||
// id + access + title + shortName + stickersCount + hash + flags
|
||||
size += sizeof(quint64) * 2 + _stringSize(i->title) + _stringSize(i->shortName) + sizeof(quint32) + sizeof(qint32) * 2;
|
||||
size += sizeof(quint64) * 2 + Serialize::stringSize(i->title) + Serialize::stringSize(i->shortName) + sizeof(quint32) + sizeof(qint32) * 2;
|
||||
for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) {
|
||||
DocumentData *doc = *j;
|
||||
|
||||
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + alt + type-of-set
|
||||
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(doc->sticker()->alt) + sizeof(qint32);
|
||||
|
||||
// loc
|
||||
size += _storageImageLocationSize();
|
||||
size += Serialize::Document::sizeInStream(*j);
|
||||
}
|
||||
|
||||
if (AppVersion > 9018) {
|
||||
size += sizeof(qint32); // emojiCount
|
||||
for (StickersByEmojiMap::const_iterator j = i->emoji.cbegin(), e = i->emoji.cend(); j != e; ++j) {
|
||||
size += _stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64));
|
||||
size += Serialize::stringSize(emojiString(j.key())) + sizeof(qint32) + (j->size() * sizeof(quint64));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3267,48 +3231,16 @@ namespace Local {
|
|||
|
||||
set.stickers.reserve(scnt);
|
||||
|
||||
QMap<uint64, bool> read;
|
||||
Serialize::Document::StickerSetInfo info(setId, setAccess, setShortName);
|
||||
OrderedSet<DocumentId> read;
|
||||
for (int32 j = 0; j < scnt; ++j) {
|
||||
quint64 id, access;
|
||||
QString name, mime, alt;
|
||||
qint32 date, dc, size, width, height, type, typeOfSet;
|
||||
stickers.stream >> id >> access >> date >> name >> mime >> dc >> size >> width >> height >> type >> alt >> typeOfSet;
|
||||
auto document = Serialize::Document::readStickerFromStream(stickers.stream, info);
|
||||
if (!document || !document->sticker()) continue;
|
||||
|
||||
StorageImageLocation thumb(_readStorageImageLocation(stickers));
|
||||
if (read.contains(document->id)) continue;
|
||||
read.insert(document->id);
|
||||
|
||||
if (read.contains(id)) continue;
|
||||
read.insert(id, true);
|
||||
|
||||
if (setId == Stickers::DefaultSetId || setId == Stickers::CustomSetId) {
|
||||
typeOfSet = StickerSetTypeEmpty;
|
||||
}
|
||||
|
||||
QVector<MTPDocumentAttribute> attributes;
|
||||
if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
|
||||
if (type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (type == StickerDocument) {
|
||||
switch (typeOfSet) {
|
||||
case StickerSetTypeID: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetID(MTP_long(setId), MTP_long(setAccess))));
|
||||
} break;
|
||||
case StickerSetTypeShortName: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(setShortName))));
|
||||
} break;
|
||||
case StickerSetTypeEmpty:
|
||||
default: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||
}
|
||||
|
||||
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb);
|
||||
if (!doc->sticker()) continue;
|
||||
|
||||
set.stickers.push_back(doc);
|
||||
set.stickers.push_back(document);
|
||||
++set.count;
|
||||
}
|
||||
|
||||
|
@ -3383,14 +3315,8 @@ namespace Local {
|
|||
_writeMap();
|
||||
} else {
|
||||
quint32 size = sizeof(quint32); // count
|
||||
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
|
||||
DocumentData *doc = *i;
|
||||
|
||||
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + duration
|
||||
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
|
||||
|
||||
// thumb
|
||||
size += _storageImageLocationSize();
|
||||
for_const (auto gif, saved) {
|
||||
size += Serialize::Document::sizeInStream(gif);
|
||||
}
|
||||
|
||||
if (!_savedGifsKey) {
|
||||
|
@ -3400,11 +3326,8 @@ namespace Local {
|
|||
}
|
||||
EncryptedDescriptor data(size);
|
||||
data.stream << quint32(saved.size());
|
||||
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
|
||||
DocumentData *doc = *i;
|
||||
|
||||
data.stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << qint32(doc->duration());
|
||||
_writeStorageImageLocation(data.stream, doc->thumb->location());
|
||||
for_const (auto gif, saved) {
|
||||
Serialize::Document::writeToStream(data.stream, gif);
|
||||
}
|
||||
FileWriteDescriptor file(_savedGifsKey);
|
||||
file.writeEncrypted(data);
|
||||
|
@ -3428,35 +3351,15 @@ namespace Local {
|
|||
quint32 cnt;
|
||||
gifs.stream >> cnt;
|
||||
saved.reserve(cnt);
|
||||
QMap<uint64, NullType> read;
|
||||
OrderedSet<DocumentId> read;
|
||||
for (uint32 i = 0; i < cnt; ++i) {
|
||||
quint64 id, access;
|
||||
QString name, mime;
|
||||
qint32 date, dc, size, width, height, type, duration;
|
||||
gifs.stream >> id >> access >> date >> name >> mime >> dc >> size >> width >> height >> type >> duration;
|
||||
DocumentData *document = Serialize::Document::readFromStream(gifs.stream);
|
||||
if (!document || !document->isAnimation()) continue;
|
||||
|
||||
StorageImageLocation thumb(_readStorageImageLocation(gifs));
|
||||
if (read.contains(document->id)) continue;
|
||||
read.insert(document->id);
|
||||
|
||||
if (read.contains(id)) continue;
|
||||
read.insert(id, NullType());
|
||||
|
||||
QVector<MTPDocumentAttribute> attributes;
|
||||
if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
|
||||
if (type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
if (duration >= 0) {
|
||||
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(width), MTP_int(height)));
|
||||
} else {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||
}
|
||||
}
|
||||
|
||||
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb);
|
||||
if (!doc->isAnimation()) continue;
|
||||
|
||||
saved.push_back(doc);
|
||||
saved.push_back(document);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3522,12 +3425,12 @@ namespace Local {
|
|||
}
|
||||
|
||||
uint32 _peerSize(PeerData *peer) {
|
||||
uint32 result = sizeof(quint64) + sizeof(quint64) + _storageImageLocationSize();
|
||||
uint32 result = sizeof(quint64) + sizeof(quint64) + Serialize::storageImageLocationSize();
|
||||
if (peer->isUser()) {
|
||||
UserData *user = peer->asUser();
|
||||
|
||||
// first + last + phone + username + access
|
||||
result += _stringSize(user->firstName) + _stringSize(user->lastName) + _stringSize(user->phone) + _stringSize(user->username) + sizeof(quint64);
|
||||
result += Serialize::stringSize(user->firstName) + Serialize::stringSize(user->lastName) + Serialize::stringSize(user->phone) + Serialize::stringSize(user->username) + sizeof(quint64);
|
||||
|
||||
// flags
|
||||
if (AppVersion >= 9012) {
|
||||
|
@ -3540,19 +3443,19 @@ namespace Local {
|
|||
ChatData *chat = peer->asChat();
|
||||
|
||||
// name + count + date + version + admin + forbidden + left + invitationUrl
|
||||
result += _stringSize(chat->name) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(chat->invitationUrl);
|
||||
result += Serialize::stringSize(chat->name) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + Serialize::stringSize(chat->invitationUrl);
|
||||
} else if (peer->isChannel()) {
|
||||
ChannelData *channel = peer->asChannel();
|
||||
|
||||
// name + access + date + version + forbidden + flags + invitationUrl
|
||||
result += _stringSize(channel->name) + sizeof(quint64) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(channel->invitationUrl);
|
||||
result += Serialize::stringSize(channel->name) + sizeof(quint64) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + Serialize::stringSize(channel->invitationUrl);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void _writePeer(QDataStream &stream, PeerData *peer) {
|
||||
stream << quint64(peer->id) << quint64(peer->photoId);
|
||||
_writeStorageImageLocation(stream, peer->photoLoc);
|
||||
Serialize::writeStorageImageLocation(stream, peer->photoLoc);
|
||||
if (peer->isUser()) {
|
||||
UserData *user = peer->asUser();
|
||||
|
||||
|
@ -3583,7 +3486,7 @@ namespace Local {
|
|||
quint64 peerId = 0, photoId = 0;
|
||||
from.stream >> peerId >> photoId;
|
||||
|
||||
StorageImageLocation photoLoc(_readStorageImageLocation(from));
|
||||
StorageImageLocation photoLoc(Serialize::readStorageImageLocation(from.stream));
|
||||
|
||||
PeerData *result = App::peerLoaded(peerId);
|
||||
bool wasLoaded = (result != nullptr);
|
||||
|
@ -3711,13 +3614,13 @@ namespace Local {
|
|||
quint32 size = sizeof(quint32) * 3, writeCnt = 0, searchCnt = 0, botsCnt = cRecentInlineBots().size();
|
||||
for (RecentHashtagPack::const_iterator i = write.cbegin(), e = write.cend(); i != e; ++i) {
|
||||
if (!i->first.isEmpty()) {
|
||||
size += _stringSize(i->first) + sizeof(quint16);
|
||||
size += Serialize::stringSize(i->first) + sizeof(quint16);
|
||||
++writeCnt;
|
||||
}
|
||||
}
|
||||
for (RecentHashtagPack::const_iterator i = search.cbegin(), e = search.cend(); i != e; ++i) {
|
||||
if (!i->first.isEmpty()) {
|
||||
size += _stringSize(i->first) + sizeof(quint16);
|
||||
size += Serialize::stringSize(i->first) + sizeof(quint16);
|
||||
++searchCnt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace Local {
|
|||
|
||||
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
void copyAudio(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasAudios();
|
||||
qint64 storageAudiosSize();
|
||||
|
||||
|
|
47
Telegram/SourceFiles/serialize/serialize_common.cpp
Normal file
47
Telegram/SourceFiles/serialize/serialize_common.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "serialize/serialize_common.h"
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
int stringSize(const QString &str) {
|
||||
return sizeof(quint32) + str.size() * sizeof(ushort);
|
||||
}
|
||||
|
||||
void writeStorageImageLocation(QDataStream &stream, const StorageImageLocation &loc) {
|
||||
stream << qint32(loc.width()) << qint32(loc.height());
|
||||
stream << qint32(loc.dc()) << quint64(loc.volume()) << qint32(loc.local()) << quint64(loc.secret());
|
||||
}
|
||||
|
||||
StorageImageLocation readStorageImageLocation(QDataStream &stream) {
|
||||
qint32 width, height, dc, local;
|
||||
quint64 volume, secret;
|
||||
stream >> width >> height >> dc >> volume >> local >> secret;
|
||||
return StorageImageLocation(width, height, dc, volume, local, secret);
|
||||
}
|
||||
|
||||
int storageImageLocationSize() {
|
||||
// width + height + dc + volume + local + secret
|
||||
return sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint64) + sizeof(qint32) + sizeof(quint64);
|
||||
}
|
||||
|
||||
} // namespace Serialize
|
33
Telegram/SourceFiles/serialize/serialize_common.h
Normal file
33
Telegram/SourceFiles/serialize/serialize_common.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/images.h"
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
int stringSize(const QString &str);
|
||||
|
||||
void writeStorageImageLocation(QDataStream &stream, const StorageImageLocation &loc);
|
||||
StorageImageLocation readStorageImageLocation(QDataStream &stream);
|
||||
int storageImageLocationSize();
|
||||
|
||||
} // namespace Serialize
|
163
Telegram/SourceFiles/serialize/serialize_document.cpp
Normal file
163
Telegram/SourceFiles/serialize/serialize_document.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "serialize/serialize_document.h"
|
||||
|
||||
#include "serialize/serialize_common.h"
|
||||
|
||||
namespace {
|
||||
|
||||
enum StickerSetType {
|
||||
StickerSetTypeEmpty = 0,
|
||||
StickerSetTypeID = 1,
|
||||
StickerSetTypeShortName = 2,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
void Document::writeToStream(QDataStream &stream, DocumentData *document) {
|
||||
stream << quint64(document->id) << quint64(document->_access) << qint32(document->date);
|
||||
stream << document->name << document->mime << qint32(document->_dc) << qint32(document->size);
|
||||
stream << qint32(document->dimensions.width()) << qint32(document->dimensions.height());
|
||||
stream << qint32(document->type);
|
||||
if (auto sticker = document->sticker()) {
|
||||
stream << document->sticker()->alt;
|
||||
switch (document->sticker()->set.type()) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
stream << qint32(StickerSetTypeID);
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
stream << qint32(StickerSetTypeShortName);
|
||||
} break;
|
||||
case mtpc_inputStickerSetEmpty:
|
||||
default: {
|
||||
stream << qint32(StickerSetTypeEmpty);
|
||||
} break;
|
||||
}
|
||||
writeStorageImageLocation(stream, document->sticker()->loc);
|
||||
} else {
|
||||
stream << qint32(document->duration());
|
||||
writeStorageImageLocation(stream, document->thumb->location());
|
||||
}
|
||||
}
|
||||
|
||||
DocumentData *Document::readFromStreamHelper(QDataStream &stream, const StickerSetInfo *info) {
|
||||
quint64 id, access;
|
||||
QString name, mime;
|
||||
qint32 date, dc, size, width, height, type;
|
||||
stream >> id >> access >> date;
|
||||
stream >> name >> mime >> dc >> size;
|
||||
stream >> width >> height;
|
||||
stream >> type;
|
||||
|
||||
QVector<MTPDocumentAttribute> attributes;
|
||||
if (!name.isEmpty()) {
|
||||
attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
|
||||
}
|
||||
|
||||
qint32 duration = -1;
|
||||
StorageImageLocation thumb;
|
||||
if (type == StickerDocument) {
|
||||
QString alt;
|
||||
qint32 typeOfSet;
|
||||
stream >> alt >> typeOfSet;
|
||||
|
||||
thumb = readStorageImageLocation(stream);
|
||||
|
||||
if (typeOfSet == StickerSetTypeEmpty) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
} else if (info) {
|
||||
if (info->setId == Stickers::DefaultSetId || info->setId == Stickers::CustomSetId) {
|
||||
typeOfSet = StickerSetTypeEmpty;
|
||||
}
|
||||
|
||||
switch (typeOfSet) {
|
||||
case StickerSetTypeID: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetID(MTP_long(info->setId), MTP_long(info->accessHash))));
|
||||
} break;
|
||||
case StickerSetTypeShortName: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(info->shortName))));
|
||||
} break;
|
||||
case StickerSetTypeEmpty:
|
||||
default: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream >> duration;
|
||||
if (type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
}
|
||||
thumb = readStorageImageLocation(stream);
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
if (duration >= 0) {
|
||||
attributes.push_back(MTP_documentAttributeVideo(MTP_int(duration), MTP_int(width), MTP_int(height)));
|
||||
} else {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!dc && !access) {
|
||||
return nullptr;
|
||||
}
|
||||
return App::documentSet(id, nullptr, access, date, attributes, mime, thumb.isNull() ? ImagePtr() : ImagePtr(thumb), dc, size, thumb);
|
||||
}
|
||||
|
||||
DocumentData *Document::readStickerFromStream(QDataStream &stream, const StickerSetInfo &info) {
|
||||
return readFromStreamHelper(stream, &info);
|
||||
}
|
||||
|
||||
DocumentData *Document::readFromStream(QDataStream &stream) {
|
||||
return readFromStreamHelper(stream, nullptr);
|
||||
}
|
||||
|
||||
int Document::sizeInStream(DocumentData *document) {
|
||||
int result = 0;
|
||||
|
||||
// id + access + date
|
||||
result += sizeof(quint64) + sizeof(quint64) + sizeof(qint32);
|
||||
// + namelen + name + mimelen + mime + dc + size
|
||||
result += stringSize(document->name) + stringSize(document->mime) + sizeof(qint32) + sizeof(qint32);
|
||||
// + width + height
|
||||
result += sizeof(qint32) + sizeof(qint32);
|
||||
// + type
|
||||
result += sizeof(qint32);
|
||||
|
||||
if (auto sticker = document->sticker()) { // type == StickerDocument
|
||||
// + altlen + alt + type-of-set
|
||||
result += stringSize(sticker->alt) + sizeof(qint32);
|
||||
// + thumb loc
|
||||
result += Serialize::storageImageLocationSize();
|
||||
} else {
|
||||
// + duration
|
||||
result += sizeof(qint32);
|
||||
// + thumb loc
|
||||
result += Serialize::storageImageLocationSize();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Serialize
|
51
Telegram/SourceFiles/serialize/serialize_document.h
Normal file
51
Telegram/SourceFiles/serialize/serialize_document.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
In addition, as a special exception, the copyright holders give permission
|
||||
to link the code of portions of this program with the OpenSSL library.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
namespace Serialize {
|
||||
|
||||
class Document {
|
||||
public:
|
||||
|
||||
struct StickerSetInfo {
|
||||
StickerSetInfo(uint64 setId, uint64 accessHash, QString shortName)
|
||||
: setId(setId)
|
||||
, accessHash(accessHash)
|
||||
, shortName(shortName) {
|
||||
}
|
||||
uint64 setId;
|
||||
uint64 accessHash;
|
||||
QString shortName;
|
||||
};
|
||||
|
||||
static void writeToStream(QDataStream &stream, DocumentData *document);
|
||||
static DocumentData *readStickerFromStream(QDataStream &stream, const StickerSetInfo &info);
|
||||
static DocumentData *readFromStream(QDataStream &stream);
|
||||
static int sizeInStream(DocumentData *document);
|
||||
|
||||
private:
|
||||
static DocumentData *readFromStreamHelper(QDataStream &stream, const StickerSetInfo *info);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Serialize
|
|
@ -986,22 +986,30 @@ VoiceData::~VoiceData() {
|
|||
}
|
||||
}
|
||||
|
||||
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) : id(id)
|
||||
, type(FileDocument)
|
||||
, access(access)
|
||||
, date(date)
|
||||
, mime(mime)
|
||||
, thumb(thumb)
|
||||
, dc(dc)
|
||||
, size(size)
|
||||
, status(FileReady)
|
||||
, uploadOffset(0)
|
||||
, _additional(0)
|
||||
, _duration(-1)
|
||||
, _actionOnLoad(ActionOnLoadNone)
|
||||
, _loader(0) {
|
||||
DocumentAdditionalData::~DocumentAdditionalData() {
|
||||
}
|
||||
|
||||
DocumentData::DocumentData(DocumentId id, int32 dc, uint64 accessHash, const QString &url, const QVector<MTPDocumentAttribute> &attributes)
|
||||
: id(id)
|
||||
, _dc(dc)
|
||||
, _access(accessHash)
|
||||
, _url(url) {
|
||||
setattributes(attributes);
|
||||
_location = Local::readFileLocation(mediaKey());
|
||||
if (_dc && _access) {
|
||||
_location = Local::readFileLocation(mediaKey());
|
||||
}
|
||||
}
|
||||
|
||||
DocumentData *DocumentData::create(DocumentId id) {
|
||||
return new DocumentData(id, 0, 0, QString(), QVector<MTPDocumentAttribute>());
|
||||
}
|
||||
|
||||
DocumentData *DocumentData::create(DocumentId id, int32 dc, uint64 accessHash, const QVector<MTPDocumentAttribute> &attributes) {
|
||||
return new DocumentData(id, dc, accessHash, QString(), attributes);
|
||||
}
|
||||
|
||||
DocumentData *DocumentData::create(DocumentId id, const QString &url, const QVector<MTPDocumentAttribute> &attributes) {
|
||||
return new DocumentData(id, 0, 0, url, attributes);
|
||||
}
|
||||
|
||||
void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
|
||||
|
@ -1013,15 +1021,13 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
|||
} break;
|
||||
case mtpc_documentAttributeAnimated: if (type == FileDocument || type == StickerDocument || type == VideoDocument) {
|
||||
type = AnimatedDocument;
|
||||
delete _additional;
|
||||
_additional = 0;
|
||||
_additional.clear();
|
||||
} break;
|
||||
case mtpc_documentAttributeSticker: {
|
||||
const auto &d(attributes[i].c_documentAttributeSticker());
|
||||
if (type == FileDocument) {
|
||||
type = StickerDocument;
|
||||
StickerData *sticker = new StickerData();
|
||||
_additional = sticker;
|
||||
_additional = MakeUnique<StickerData>();
|
||||
}
|
||||
if (sticker()) {
|
||||
sticker()->alt = qs(d.valt);
|
||||
|
@ -1041,12 +1047,10 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
|||
if (type == FileDocument) {
|
||||
if (d.is_voice()) {
|
||||
type = VoiceDocument;
|
||||
VoiceData *voice = new VoiceData();
|
||||
_additional = voice;
|
||||
_additional = MakeUnique<VoiceData>();
|
||||
} else {
|
||||
type = SongDocument;
|
||||
SongData *song = new SongData();
|
||||
_additional = song;
|
||||
_additional = MakeUnique<SongData>();
|
||||
}
|
||||
}
|
||||
if (voice()) {
|
||||
|
@ -1071,8 +1075,7 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
|||
if (type == StickerDocument) {
|
||||
if (dimensions.width() <= 0 || dimensions.height() <= 0 || dimensions.width() > StickerMaxSize || dimensions.height() > StickerMaxSize || size > StickerInMemory) {
|
||||
type = FileDocument;
|
||||
delete _additional;
|
||||
_additional = 0;
|
||||
_additional.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1203,7 +1206,7 @@ bool DocumentData::loaded(FilePathResolveType type) const {
|
|||
if (loading() && _loader->done()) {
|
||||
if (_loader->fileType() == mtpc_storage_fileUnknown) {
|
||||
_loader->deleteLater();
|
||||
_loader->rpcClear();
|
||||
_loader->stop();
|
||||
_loader = CancelledMtpFileLoader;
|
||||
} else {
|
||||
DocumentData *that = const_cast<DocumentData*>(this);
|
||||
|
@ -1214,8 +1217,8 @@ bool DocumentData::loaded(FilePathResolveType type) const {
|
|||
}
|
||||
|
||||
_loader->deleteLater();
|
||||
_loader->rpcClear();
|
||||
_loader = 0;
|
||||
_loader->stop();
|
||||
_loader = nullptr;
|
||||
}
|
||||
notifyLayoutChanged();
|
||||
}
|
||||
|
@ -1284,7 +1287,11 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs
|
|||
if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud();
|
||||
} else {
|
||||
status = FileReady;
|
||||
_loader = new mtpFileLoader(dc, id, access, locationType(), toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading);
|
||||
if (!_access && !_url.isEmpty()) {
|
||||
_loader = new webFileLoader(_url, toFile, fromCloud, autoLoading);
|
||||
} else {
|
||||
_loader = new mtpFileLoader(_dc, id, _access, locationType(), toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading);
|
||||
}
|
||||
_loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(documentLoadProgress(FileLoader*)));
|
||||
_loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool)));
|
||||
_loader->start();
|
||||
|
@ -1295,12 +1302,12 @@ void DocumentData::save(const QString &toFile, ActionOnLoad action, const FullMs
|
|||
void DocumentData::cancel() {
|
||||
if (!loading()) return;
|
||||
|
||||
mtpFileLoader *l = _loader;
|
||||
FileLoader *l = _loader;
|
||||
_loader = CancelledMtpFileLoader;
|
||||
if (l) {
|
||||
l->cancel();
|
||||
l->deleteLater();
|
||||
l->rpcClear();
|
||||
l->stop();
|
||||
|
||||
notifyLayoutChanged();
|
||||
}
|
||||
|
@ -1418,13 +1425,27 @@ void DocumentData::recountIsImage() {
|
|||
_duration = fileIsImage(name, mime) ? 1 : -1; // hack
|
||||
}
|
||||
|
||||
DocumentData::~DocumentData() {
|
||||
delete _additional;
|
||||
void DocumentData::setRemoteLocation(int32 dc, uint64 access) {
|
||||
_dc = dc;
|
||||
_access = access;
|
||||
if (isValid()) {
|
||||
if (_location.check()) {
|
||||
Local::writeFileLocation(mediaKey(), _location);
|
||||
} else {
|
||||
_location = Local::readFileLocation(mediaKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentData::setContentUrl(const QString &url) {
|
||||
_url = url;
|
||||
}
|
||||
|
||||
DocumentData::~DocumentData() {
|
||||
if (loading()) {
|
||||
_loader->deleteLater();
|
||||
_loader->stop();
|
||||
_loader = 0;
|
||||
_loader = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -954,6 +954,7 @@ enum DocumentType {
|
|||
};
|
||||
|
||||
struct DocumentAdditionalData {
|
||||
virtual ~DocumentAdditionalData();
|
||||
};
|
||||
|
||||
struct StickerData : public DocumentAdditionalData {
|
||||
|
@ -989,9 +990,16 @@ struct VoiceData : public DocumentAdditionalData {
|
|||
|
||||
bool fileIsImage(const QString &name, const QString &mime);
|
||||
|
||||
namespace Serialize {
|
||||
class Document;
|
||||
} // namespace Serialize;
|
||||
|
||||
class DocumentData {
|
||||
public:
|
||||
DocumentData(const DocumentId &id, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
|
||||
static DocumentData *create(DocumentId id);
|
||||
static DocumentData *create(DocumentId id, int32 dc, uint64 accessHash, const QVector<MTPDocumentAttribute> &attributes);
|
||||
static DocumentData *create(DocumentId id, const QString &url, const QVector<MTPDocumentAttribute> &attributes);
|
||||
|
||||
void setattributes(const QVector<MTPDocumentAttribute> &attributes);
|
||||
|
||||
void automaticLoad(const HistoryItem *item); // auto load sticker or video
|
||||
|
@ -1026,7 +1034,7 @@ public:
|
|||
ImagePtr makeReplyPreview();
|
||||
|
||||
StickerData *sticker() {
|
||||
return (type == StickerDocument) ? static_cast<StickerData*>(_additional) : nullptr;
|
||||
return (type == StickerDocument) ? static_cast<StickerData*>(_additional.data()) : nullptr;
|
||||
}
|
||||
void checkSticker() {
|
||||
StickerData *s = sticker();
|
||||
|
@ -1046,16 +1054,16 @@ public:
|
|||
}
|
||||
}
|
||||
SongData *song() {
|
||||
return (type == SongDocument) ? static_cast<SongData*>(_additional) : nullptr;
|
||||
return (type == SongDocument) ? static_cast<SongData*>(_additional.data()) : nullptr;
|
||||
}
|
||||
const SongData *song() const {
|
||||
return (type == SongDocument) ? static_cast<const SongData*>(_additional) : nullptr;
|
||||
return (type == SongDocument) ? static_cast<const SongData*>(_additional.data()) : nullptr;
|
||||
}
|
||||
VoiceData *voice() {
|
||||
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional) : nullptr;
|
||||
return (type == VoiceDocument) ? static_cast<VoiceData*>(_additional.data()) : nullptr;
|
||||
}
|
||||
const VoiceData *voice() const {
|
||||
return (type == VoiceDocument) ? static_cast<const VoiceData*>(_additional) : nullptr;
|
||||
return (type == VoiceDocument) ? static_cast<const VoiceData*>(_additional.data()) : nullptr;
|
||||
}
|
||||
bool isAnimation() const {
|
||||
return (type == AnimatedDocument) || !mime.compare(qstr("image/gif"), Qt::CaseInsensitive);
|
||||
|
@ -1064,7 +1072,7 @@ public:
|
|||
return (type == AnimatedDocument) && !mime.compare(qstr("video/mp4"), Qt::CaseInsensitive);
|
||||
}
|
||||
bool isMusic() const {
|
||||
return (type == SongDocument) ? !static_cast<SongData*>(_additional)->title.isEmpty() : false;
|
||||
return (type == SongDocument) ? !static_cast<SongData*>(_additional.data())->title.isEmpty() : false;
|
||||
}
|
||||
bool isVideo() const {
|
||||
return (type == VideoDocument);
|
||||
|
@ -1080,41 +1088,59 @@ public:
|
|||
_data = data;
|
||||
}
|
||||
|
||||
void setRemoteLocation(int32 dc, uint64 access);
|
||||
void setContentUrl(const QString &url);
|
||||
bool isValid() const {
|
||||
return (_dc != 0 && _access != 0) || !_url.isEmpty();
|
||||
}
|
||||
MTPInputDocument mtpInput() const {
|
||||
if (_access) {
|
||||
return MTP_inputDocument(MTP_long(id), MTP_long(_access));
|
||||
}
|
||||
return MTP_inputDocumentEmpty();
|
||||
}
|
||||
|
||||
~DocumentData();
|
||||
|
||||
DocumentId id;
|
||||
DocumentType type;
|
||||
DocumentType type = FileDocument;
|
||||
QSize dimensions;
|
||||
uint64 access;
|
||||
int32 date;
|
||||
int32 date = 0;
|
||||
QString name, mime;
|
||||
ImagePtr thumb, replyPreview;
|
||||
int32 dc;
|
||||
int32 size;
|
||||
int32 size = 0;
|
||||
|
||||
FileStatus status;
|
||||
int32 uploadOffset;
|
||||
FileStatus status = FileReady;
|
||||
int32 uploadOffset = 0;
|
||||
|
||||
int32 md5[8];
|
||||
|
||||
MediaKey mediaKey() const {
|
||||
return ::mediaKey(locationType(), dc, id);
|
||||
return ::mediaKey(locationType(), _dc, id);
|
||||
}
|
||||
|
||||
private:
|
||||
DocumentData(DocumentId id, int32 dc, uint64 accessHash, const QString &url, const QVector<MTPDocumentAttribute> &attributes);
|
||||
|
||||
FileLocation _location;
|
||||
QByteArray _data;
|
||||
DocumentAdditionalData *_additional;
|
||||
int32 _duration;
|
||||
friend class Serialize::Document;
|
||||
|
||||
LocationType locationType() const {
|
||||
return voice() ? AudioFileLocation : (isVideo() ? VideoFileLocation : DocumentFileLocation);
|
||||
}
|
||||
|
||||
ActionOnLoad _actionOnLoad;
|
||||
// Two types of location: from MTProto by dc+access or from web by url
|
||||
int32 _dc = 0;
|
||||
uint64 _access = 0;
|
||||
QString _url;
|
||||
|
||||
FileLocation _location;
|
||||
QByteArray _data;
|
||||
UniquePointer<DocumentAdditionalData> _additional;
|
||||
int32 _duration = -1;
|
||||
|
||||
ActionOnLoad _actionOnLoad = ActionOnLoadNone;
|
||||
FullMsgId _actionOnLoadMsgId;
|
||||
mutable mtpFileLoader *_loader;
|
||||
mutable FileLoader *_loader = nullptr;
|
||||
|
||||
void notifyLayoutChanged() const;
|
||||
|
||||
|
|
|
@ -1124,6 +1124,8 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\serialize\serialize_common.cpp" />
|
||||
<ClCompile Include="SourceFiles\serialize\serialize_document.cpp" />
|
||||
<ClCompile Include="SourceFiles\settings.cpp" />
|
||||
<ClCompile Include="SourceFiles\settingswidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\shortcuts.cpp" />
|
||||
|
@ -1329,6 +1331,8 @@
|
|||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/session.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="SourceFiles\serialize\serialize_common.h" />
|
||||
<ClInclude Include="SourceFiles\serialize\serialize_document.h" />
|
||||
<ClInclude Include="SourceFiles\shortcuts.h" />
|
||||
<CustomBuild Include="SourceFiles\ui\animation.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
<Filter Include="ui\toast">
|
||||
<UniqueIdentifier>{815de139-ef13-45d6-a131-a3556eefae55}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="serialize">
|
||||
<UniqueIdentifier>{e9244e0a-a3ae-43dc-8a72-fd7d14cee20b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="SourceFiles\main.cpp">
|
||||
|
@ -1008,6 +1011,12 @@
|
|||
<ClCompile Include="SourceFiles\ui\toast\toast_widget.cpp">
|
||||
<Filter>ui\toast</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\serialize\serialize_document.cpp">
|
||||
<Filter>serialize</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\serialize\serialize_common.cpp">
|
||||
<Filter>serialize</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SourceFiles\stdafx.h">
|
||||
|
@ -1124,6 +1133,12 @@
|
|||
<ClInclude Include="SourceFiles\ui\toast\toast_widget.h">
|
||||
<Filter>ui\toast</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SourceFiles\serialize\serialize_document.h">
|
||||
<Filter>serialize</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SourceFiles\serialize\serialize_common.h">
|
||||
<Filter>serialize</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="SourceFiles\application.h">
|
||||
|
|
Loading…
Add table
Reference in a new issue