Encapsulated DocumentData location and serialization.

DocumentData now can point to mtproto or http file.
This commit is contained in:
John Preston 2016-04-09 09:57:55 +04:00
parent ff839bd978
commit 0894931fa1
16 changed files with 514 additions and 236 deletions

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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>();

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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();

View 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

View 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

View 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

View 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

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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>

View file

@ -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">