2018-10-23 09:44:42 +00:00
/*
This file is part of Telegram Desktop ,
the official desktop application for the Telegram messaging service .
For license and copyright information please follow this link :
https : //github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
# include "ui/image/image_location.h"
# include "ui/image/image.h"
# include "platform/platform_specific.h"
2019-03-22 14:19:43 +00:00
# include "storage/cache/storage_cache_types.h"
# include "storage/serialize_common.h"
# include "data/data_file_origin.h"
2019-05-20 14:57:25 +00:00
# include "base/overload.h"
2019-07-24 11:45:24 +00:00
# include "main/main_session.h"
2019-03-22 14:19:43 +00:00
2019-09-04 07:19:15 +00:00
# include <QtCore/QBuffer>
2019-03-22 14:19:43 +00:00
namespace {
2019-03-25 09:17:47 +00:00
constexpr auto kDocumentBaseCacheTag = 0x0000000000010000ULL ;
constexpr auto kDocumentBaseCacheMask = 0x000000000000FF00ULL ;
2019-05-20 14:57:25 +00:00
constexpr auto kSerializeTypeShift = quint8 ( 0x08 ) ;
2019-05-31 16:45:03 +00:00
const auto kInMediaCacheLocation = QString ( " *media_cache* " ) ;
2019-03-25 09:17:47 +00:00
2019-05-20 14:57:25 +00:00
MTPInputPeer GenerateInputPeer (
uint64 id ,
uint64 accessHash ,
int32 inMessagePeerId ,
int32 inMessageId ,
int32 self ) {
2019-03-22 14:19:43 +00:00
const auto bareId = [ & ] {
return peerToBareMTPInt ( id ) ;
} ;
2019-05-20 14:57:25 +00:00
if ( inMessagePeerId > 0 & & inMessageId ) {
return MTP_inputPeerUserFromMessage (
GenerateInputPeer ( id , accessHash , 0 , 0 , self ) ,
MTP_int ( inMessageId ) ,
MTP_int ( inMessagePeerId ) ) ;
} else if ( inMessagePeerId < 0 & & inMessageId ) {
return MTP_inputPeerChannelFromMessage (
GenerateInputPeer ( id , accessHash , 0 , 0 , self ) ,
MTP_int ( inMessageId ) ,
MTP_int ( - inMessagePeerId ) ) ;
} else if ( ! id ) {
2019-03-22 14:19:43 +00:00
return MTP_inputPeerEmpty ( ) ;
} else if ( id = = peerFromUser ( self ) ) {
return MTP_inputPeerSelf ( ) ;
} else if ( peerIsUser ( id ) ) {
return MTP_inputPeerUser ( bareId ( ) , MTP_long ( accessHash ) ) ;
} else if ( peerIsChat ( id ) ) {
return MTP_inputPeerChat ( bareId ( ) ) ;
} else if ( peerIsChannel ( id ) ) {
return MTP_inputPeerChannel ( bareId ( ) , MTP_long ( accessHash ) ) ;
} else {
return MTP_inputPeerEmpty ( ) ;
}
}
} // namespace
2018-10-23 09:44:42 +00:00
2019-02-17 08:31:04 +00:00
ImagePtr : : ImagePtr ( ) : _data ( Image : : Empty ( ) ) {
2018-10-23 09:44:42 +00:00
}
ImagePtr : : ImagePtr ( not_null < Image * > data ) : _data ( data ) {
}
Image * ImagePtr : : operator - > ( ) const {
return _data ;
}
Image * ImagePtr : : get ( ) const {
return _data ;
}
ImagePtr : : operator bool ( ) const {
return ! _data - > isNull ( ) ;
}
WebFileLocation WebFileLocation : : Null ;
2019-03-22 14:19:43 +00:00
StorageFileLocation : : StorageFileLocation (
int32 dcId ,
int32 self ,
const MTPInputFileLocation & tl )
: _dcId ( dcId ) {
tl . match ( [ & ] ( const MTPDinputFileLocation & data ) {
_type = Type : : Legacy ;
2019-07-05 13:38:38 +00:00
_volumeId = data . vvolume_id ( ) . v ;
_localId = data . vlocal_id ( ) . v ;
_accessHash = data . vsecret ( ) . v ;
_fileReference = data . vfile_reference ( ) . v ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputEncryptedFileLocation & data ) {
_type = Type : : Encrypted ;
2019-07-05 13:38:38 +00:00
_id = data . vid ( ) . v ;
_accessHash = data . vaccess_hash ( ) . v ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputDocumentFileLocation & data ) {
_type = Type : : Document ;
2019-07-05 13:38:38 +00:00
_id = data . vid ( ) . v ;
_accessHash = data . vaccess_hash ( ) . v ;
_fileReference = data . vfile_reference ( ) . v ;
_sizeLetter = data . vthumb_size ( ) . v . isEmpty ( )
2019-03-22 14:19:43 +00:00
? uint8 ( 0 )
2019-07-05 13:38:38 +00:00
: uint8 ( data . vthumb_size ( ) . v [ 0 ] ) ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputSecureFileLocation & data ) {
_type = Type : : Secure ;
2019-07-05 13:38:38 +00:00
_id = data . vid ( ) . v ;
_accessHash = data . vaccess_hash ( ) . v ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputTakeoutFileLocation & data ) {
_type = Type : : Takeout ;
} , [ & ] ( const MTPDinputPhotoFileLocation & data ) {
_type = Type : : Photo ;
2019-07-05 13:38:38 +00:00
_id = data . vid ( ) . v ;
_accessHash = data . vaccess_hash ( ) . v ;
_fileReference = data . vfile_reference ( ) . v ;
_sizeLetter = data . vthumb_size ( ) . v . isEmpty ( )
2019-03-22 14:19:43 +00:00
? char ( 0 )
2019-07-05 13:38:38 +00:00
: data . vthumb_size ( ) . v [ 0 ] ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputPeerPhotoFileLocation & data ) {
_type = Type : : PeerPhoto ;
2019-05-20 14:57:25 +00:00
const auto fillPeer = base : : overload ( [ & ] (
const MTPDinputPeerEmpty & data ) {
2019-03-22 14:19:43 +00:00
_id = 0 ;
2019-05-20 14:57:25 +00:00
} , [ & ] ( const MTPDinputPeerSelf & data ) {
2019-03-22 14:19:43 +00:00
_id = peerFromUser ( self ) ;
2019-05-20 14:57:25 +00:00
} , [ & ] ( const MTPDinputPeerChat & data ) {
2019-07-05 13:38:38 +00:00
_id = peerFromChat ( data . vchat_id ( ) ) ;
2019-05-20 14:57:25 +00:00
} , [ & ] ( const MTPDinputPeerUser & data ) {
2019-07-05 13:38:38 +00:00
_id = peerFromUser ( data . vuser_id ( ) ) ;
_accessHash = data . vaccess_hash ( ) . v ;
2019-05-20 14:57:25 +00:00
} , [ & ] ( const MTPDinputPeerChannel & data ) {
2019-07-05 13:38:38 +00:00
_id = peerFromChannel ( data . vchannel_id ( ) ) ;
_accessHash = data . vaccess_hash ( ) . v ;
2019-03-22 14:19:43 +00:00
} ) ;
2019-07-05 13:38:38 +00:00
data . vpeer ( ) . match ( fillPeer , [ & ] (
2019-05-20 14:57:25 +00:00
const MTPDinputPeerUserFromMessage & data ) {
2019-07-05 13:38:38 +00:00
data . vpeer ( ) . match ( fillPeer , [ & ] ( auto & & ) {
2019-05-20 14:57:25 +00:00
// Bad data provided.
_id = _accessHash = 0 ;
} ) ;
2019-07-05 13:38:38 +00:00
_inMessagePeerId = data . vuser_id ( ) . v ;
_inMessageId = data . vmsg_id ( ) . v ;
2019-05-20 14:57:25 +00:00
} , [ & ] ( const MTPDinputPeerChannelFromMessage & data ) {
2019-07-05 13:38:38 +00:00
data . vpeer ( ) . match ( fillPeer , [ & ] ( auto & & ) {
2019-05-20 14:57:25 +00:00
// Bad data provided.
_id = _accessHash = 0 ;
} ) ;
2019-07-05 13:38:38 +00:00
_inMessagePeerId = - data . vchannel_id ( ) . v ;
_inMessageId = data . vmsg_id ( ) . v ;
2019-05-20 14:57:25 +00:00
} ) ;
2019-07-05 13:38:38 +00:00
_volumeId = data . vvolume_id ( ) . v ;
_localId = data . vlocal_id ( ) . v ;
2019-03-22 14:19:43 +00:00
_sizeLetter = data . is_big ( ) ? ' c ' : ' a ' ;
} , [ & ] ( const MTPDinputStickerSetThumb & data ) {
_type = Type : : StickerSetThumb ;
2019-07-05 13:38:38 +00:00
data . vstickerset ( ) . match ( [ & ] ( const MTPDinputStickerSetEmpty & data ) {
2019-03-22 14:19:43 +00:00
_id = 0 ;
} , [ & ] ( const MTPDinputStickerSetID & data ) {
2019-07-05 13:38:38 +00:00
_id = data . vid ( ) . v ;
_accessHash = data . vaccess_hash ( ) . v ;
2019-03-22 14:19:43 +00:00
} , [ & ] ( const MTPDinputStickerSetShortName & data ) {
2019-08-01 09:22:49 +00:00
Unexpected ( " inputStickerSetShortName in StorageFileLocation. " ) ;
} , [ & ] ( const MTPDinputStickerSetAnimatedEmoji & data ) {
Unexpected (
" inputStickerSetAnimatedEmoji in StorageFileLocation. " ) ;
2019-03-22 14:19:43 +00:00
} ) ;
2019-07-05 13:38:38 +00:00
_volumeId = data . vvolume_id ( ) . v ;
_localId = data . vlocal_id ( ) . v ;
2019-03-22 14:19:43 +00:00
} ) ;
}
StorageFileLocation StorageFileLocation : : convertToModern (
Type type ,
uint64 id ,
uint64 accessHash ) const {
Expects ( _type = = Type : : Legacy ) ;
2019-04-03 20:05:29 +00:00
Expects ( type = = Type : : PeerPhoto | | type = = Type : : StickerSetThumb ) ;
2019-03-22 14:19:43 +00:00
auto result = * this ;
result . _type = type ;
result . _id = id ;
result . _accessHash = accessHash ;
result . _sizeLetter = ( type = = Type : : PeerPhoto ) ? uint8 ( ' a ' ) : uint8 ( 0 ) ;
return result ;
}
int32 StorageFileLocation : : dcId ( ) const {
return _dcId ;
}
2019-03-25 11:50:42 +00:00
uint64 StorageFileLocation : : objectId ( ) const {
return _id ;
}
2019-03-22 14:19:43 +00:00
MTPInputFileLocation StorageFileLocation : : tl ( int32 self ) const {
switch ( _type ) {
case Type : : Legacy :
return MTP_inputFileLocation (
MTP_long ( _volumeId ) ,
MTP_int ( _localId ) ,
MTP_long ( _accessHash ) ,
MTP_bytes ( _fileReference ) ) ;
case Type : : Encrypted :
return MTP_inputSecureFileLocation (
MTP_long ( _id ) ,
MTP_long ( _accessHash ) ) ;
case Type : : Document :
return MTP_inputDocumentFileLocation (
MTP_long ( _id ) ,
MTP_long ( _accessHash ) ,
MTP_bytes ( _fileReference ) ,
MTP_string ( _sizeLetter
? std : : string ( 1 , char ( _sizeLetter ) )
: std : : string ( ) ) ) ;
case Type : : Secure :
return MTP_inputSecureFileLocation (
MTP_long ( _id ) ,
MTP_long ( _accessHash ) ) ;
case Type : : Takeout :
return MTP_inputTakeoutFileLocation ( ) ;
case Type : : Photo :
return MTP_inputPhotoFileLocation (
MTP_long ( _id ) ,
MTP_long ( _accessHash ) ,
MTP_bytes ( _fileReference ) ,
MTP_string ( std : : string ( 1 , char ( _sizeLetter ) ) ) ) ;
case Type : : PeerPhoto :
return MTP_inputPeerPhotoFileLocation (
MTP_flags ( ( _sizeLetter = = ' c ' )
? MTPDinputPeerPhotoFileLocation : : Flag : : f_big
: MTPDinputPeerPhotoFileLocation : : Flag ( 0 ) ) ,
2019-05-20 14:57:25 +00:00
GenerateInputPeer (
_id ,
_accessHash ,
_inMessagePeerId ,
_inMessageId ,
self ) ,
2019-03-22 14:19:43 +00:00
MTP_long ( _volumeId ) ,
MTP_int ( _localId ) ) ;
case Type : : StickerSetThumb :
return MTP_inputStickerSetThumb (
MTP_inputStickerSetID ( MTP_long ( _id ) , MTP_long ( _accessHash ) ) ,
MTP_long ( _volumeId ) ,
MTP_int ( _localId ) ) ;
}
Unexpected ( " Type in StorageFileLocation::tl. " ) ;
}
QByteArray StorageFileLocation : : serialize ( ) const {
auto result = QByteArray ( ) ;
result . reserve ( serializeSize ( ) ) ;
if ( valid ( ) ) {
auto buffer = QBuffer ( & result ) ;
buffer . open ( QIODevice : : WriteOnly ) ;
auto stream = QDataStream ( & buffer ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream
< < quint16 ( _dcId )
2019-05-30 15:04:18 +00:00
< < quint8 ( kSerializeTypeShift | quint8 ( _type ) )
2019-03-22 14:19:43 +00:00
< < quint8 ( _sizeLetter )
< < qint32 ( _localId )
< < quint64 ( _id )
< < quint64 ( _accessHash )
< < quint64 ( _volumeId )
2019-05-20 14:57:25 +00:00
< < qint32 ( _inMessagePeerId )
< < qint32 ( _inMessageId )
2019-03-22 14:19:43 +00:00
< < _fileReference ;
}
return result ;
}
int StorageFileLocation : : serializeSize ( ) const {
return valid ( )
2019-05-20 14:57:25 +00:00
? int ( sizeof ( uint64 ) * 5 + Serialize : : bytearraySize ( _fileReference ) )
2019-03-22 14:19:43 +00:00
: 0 ;
}
std : : optional < StorageFileLocation > StorageFileLocation : : FromSerialized (
2019-05-20 14:57:25 +00:00
const QByteArray & serialized ) {
2019-03-22 14:19:43 +00:00
if ( serialized . isEmpty ( ) ) {
return StorageFileLocation ( ) ;
}
quint16 dcId = 0 ;
quint8 type = 0 ;
quint8 sizeLetter = 0 ;
qint32 localId = 0 ;
quint64 id = 0 ;
quint64 accessHash = 0 ;
quint64 volumeId = 0 ;
2019-05-20 14:57:25 +00:00
qint32 inMessagePeerId = 0 ;
qint32 inMessageId = 0 ;
2019-03-22 14:19:43 +00:00
QByteArray fileReference ;
auto stream = QDataStream ( serialized ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream
> > dcId
> > type
> > sizeLetter
> > localId
> > id
> > accessHash
2019-05-20 14:57:25 +00:00
> > volumeId ;
if ( type & kSerializeTypeShift ) {
type & = ~ kSerializeTypeShift ;
stream > > inMessagePeerId > > inMessageId ;
}
stream > > fileReference ;
2019-03-22 14:19:43 +00:00
auto result = StorageFileLocation ( ) ;
result . _dcId = dcId ;
result . _type = Type ( type ) ;
result . _sizeLetter = sizeLetter ;
result . _localId = localId ;
result . _id = id ;
result . _accessHash = accessHash ;
result . _volumeId = volumeId ;
2019-05-20 14:57:25 +00:00
result . _inMessagePeerId = inMessagePeerId ;
result . _inMessageId = inMessageId ;
2019-03-22 14:19:43 +00:00
result . _fileReference = fileReference ;
return ( stream . status ( ) = = QDataStream : : Ok & & result . valid ( ) )
? std : : make_optional ( result )
: std : : nullopt ;
}
StorageFileLocation : : Type StorageFileLocation : : type ( ) const {
return _type ;
}
2019-03-22 13:43:34 +00:00
bool StorageFileLocation : : valid ( ) const {
switch ( _type ) {
2019-03-22 14:19:43 +00:00
case Type : : Legacy :
2019-03-22 13:43:34 +00:00
return ( _dcId ! = 0 ) & & ( _volumeId ! = 0 ) & & ( _localId ! = 0 ) ;
case Type : : Encrypted :
case Type : : Secure :
case Type : : Document :
return ( _dcId ! = 0 ) & & ( _id ! = 0 ) ;
case Type : : Photo :
return ( _dcId ! = 0 ) & & ( _id ! = 0 ) & & ( _sizeLetter ! = 0 ) ;
case Type : : Takeout :
return true ;
case Type : : PeerPhoto :
case Type : : StickerSetThumb :
return ( _dcId ! = 0 ) & & ( _id ! = 0 ) ;
}
return false ;
}
2019-04-03 20:05:29 +00:00
bool StorageFileLocation : : isDocumentThumbnail ( ) const {
return ( _type = = Type : : Document ) & & ( _sizeLetter ! = 0 ) ;
}
2019-03-22 14:19:43 +00:00
Storage : : Cache : : Key StorageFileLocation : : cacheKey ( ) const {
using Key = Storage : : Cache : : Key ;
2019-04-03 20:05:29 +00:00
// Skip '1' for legacy document cache keys.
// Skip '2' because it is used for good (fullsize) document thumbnails.
2019-03-22 14:19:43 +00:00
const auto shifted = ( ( uint64 ( _type ) + 3 ) < < 8 ) ;
const auto sliced = uint64 ( _dcId ) & 0xFFULL ;
2019-03-22 13:43:34 +00:00
switch ( _type ) {
2019-03-22 14:19:43 +00:00
case Type : : Legacy :
2019-03-22 13:43:34 +00:00
case Type : : PeerPhoto :
case Type : : StickerSetThumb :
2019-03-22 14:19:43 +00:00
return Key {
shifted | sliced | ( uint64 ( uint32 ( _localId ) ) < < 16 ) ,
_volumeId } ;
2019-03-22 13:43:34 +00:00
case Type : : Encrypted :
case Type : : Secure :
2019-03-22 14:19:43 +00:00
return Key { shifted | sliced , _id } ;
2019-03-22 13:43:34 +00:00
case Type : : Document :
2019-04-03 20:05:29 +00:00
// Keep old cache keys for documents.
2019-03-22 14:19:43 +00:00
if ( _sizeLetter = = 0 ) {
return Data : : DocumentCacheKey ( _dcId , _id ) ;
//return Key{ 0x100ULL | sliced, _id };
}
[[fallthrough]] ;
2019-03-22 13:43:34 +00:00
case Type : : Photo :
2019-03-22 14:19:43 +00:00
return Key { shifted | sliced | ( uint64 ( _sizeLetter ) < < 16 ) , _id } ;
2019-03-22 13:43:34 +00:00
case Type : : Takeout :
2019-03-22 14:19:43 +00:00
return Key { shifted , 0 } ;
2019-03-22 13:43:34 +00:00
}
2019-03-22 14:19:43 +00:00
return Key ( ) ;
}
2019-03-25 09:17:47 +00:00
Storage : : Cache : : Key StorageFileLocation : : bigFileBaseCacheKey ( ) const {
// Skip '1' and '2' for legacy document cache keys.
const auto shifted = ( ( uint64 ( _type ) + 3 ) < < 8 ) ;
const auto sliced = uint64 ( _dcId ) & 0xFFULL ;
switch ( _type ) {
case Type : : Document : {
const auto high = kDocumentBaseCacheTag
| ( ( uint64 ( _dcId ) < < 16 ) & kDocumentBaseCacheMask )
| ( _id > > 48 ) ;
const auto low = ( _id < < 16 ) ;
Ensures ( ( low & 0xFFULL ) = = 0 ) ;
return Storage : : Cache : : Key { high , low } ;
}
2019-07-02 11:46:37 +00:00
case Type : : StickerSetThumb : {
const auto high = ( uint64 ( uint32 ( _localId ) ) < < 24 )
| ( ( uint64 ( _type ) + 1 ) < < 16 )
| ( ( uint64 ( _dcId ) & 0xFFULL ) < < 8 )
| ( _volumeId > > 56 ) ;
const auto low = ( _volumeId < < 8 ) ;
return Storage : : Cache : : Key { high , low } ;
}
2019-03-25 09:17:47 +00:00
case Type : : Legacy :
case Type : : PeerPhoto :
case Type : : Encrypted :
case Type : : Secure :
case Type : : Photo :
case Type : : Takeout :
Unexpected ( " Not implemented file location type. " ) ;
} ;
Unexpected ( " Invalid file location type. " ) ;
}
2019-03-22 14:19:43 +00:00
QByteArray StorageFileLocation : : fileReference ( ) const {
return _fileReference ;
}
bool StorageFileLocation : : refreshFileReference (
const Data : : UpdatedFileReferences & updates ) {
const auto i = ( _type = = Type : : Document )
? updates . data . find ( Data : : DocumentFileLocationId { _id } )
: ( _type = = Type : : Photo )
? updates . data . find ( Data : : PhotoFileLocationId { _id } )
: end ( updates . data ) ;
return ( i ! = end ( updates . data ) )
? refreshFileReference ( i - > second )
: false ;
}
bool StorageFileLocation : : refreshFileReference ( const QByteArray & data ) {
if ( data . isEmpty ( ) | | _fileReference = = data ) {
return false ;
}
_fileReference = data ;
return true ;
}
const StorageFileLocation & StorageFileLocation : : Invalid ( ) {
static auto result = StorageFileLocation ( ) ;
return result ;
2019-03-22 13:43:34 +00:00
}
bool operator = = ( const StorageFileLocation & a , const StorageFileLocation & b ) {
const auto valid = a . valid ( ) ;
if ( valid ! = b . valid ( ) ) {
return false ;
} else if ( ! valid ) {
return true ;
}
const auto type = a . _type ;
if ( type ! = b . _type ) {
return false ;
}
using Type = StorageFileLocation : : Type ;
switch ( type ) {
2019-03-22 14:19:43 +00:00
case Type : : Legacy :
2019-03-22 13:43:34 +00:00
return ( a . _dcId = = b . _dcId )
& & ( a . _volumeId = = b . _volumeId )
& & ( a . _localId = = b . _localId ) ;
case Type : : Encrypted :
case Type : : Secure :
return ( a . _dcId = = b . _dcId ) & & ( a . _id = = b . _id ) ;
case Type : : Photo :
case Type : : Document :
return ( a . _dcId = = b . _dcId )
& & ( a . _id = = b . _id )
& & ( a . _sizeLetter = = b . _sizeLetter ) ;
case Type : : Takeout :
return true ;
case Type : : PeerPhoto :
return ( a . _dcId = = b . _dcId )
& & ( a . _volumeId = = b . _volumeId )
& & ( a . _localId = = b . _localId )
& & ( a . _id = = b . _id )
& & ( a . _sizeLetter = = b . _sizeLetter ) ;
case Type : : StickerSetThumb :
return ( a . _dcId = = b . _dcId )
& & ( a . _volumeId = = b . _volumeId )
& & ( a . _localId = = b . _localId )
& & ( a . _id = = b . _id ) ;
} ;
Unexpected ( " Type in StorageFileLocation::operator==. " ) ;
2018-10-23 09:44:42 +00:00
}
2019-04-12 12:33:21 +00:00
bool operator < ( const StorageFileLocation & a , const StorageFileLocation & b ) {
const auto valid = a . valid ( ) ;
if ( valid ! = b . valid ( ) ) {
return ! valid ;
} else if ( ! valid ) {
return false ;
}
const auto type = a . _type ;
if ( type ! = b . _type ) {
return ( type < b . _type ) ;
}
using Type = StorageFileLocation : : Type ;
switch ( type ) {
case Type : : Legacy :
return std : : tie ( a . _localId , a . _volumeId , a . _dcId )
< std : : tie ( b . _localId , b . _volumeId , b . _dcId ) ;
case Type : : Encrypted :
case Type : : Secure :
return std : : tie ( a . _id , a . _dcId ) < std : : tie ( b . _id , b . _dcId ) ;
case Type : : Photo :
case Type : : Document :
return std : : tie ( a . _id , a . _dcId , a . _sizeLetter )
< std : : tie ( b . _id , b . _dcId , b . _sizeLetter ) ;
case Type : : Takeout :
return false ;
case Type : : PeerPhoto :
return std : : tie (
a . _id ,
a . _sizeLetter ,
a . _localId ,
a . _volumeId ,
a . _dcId )
< std : : tie (
b . _id ,
b . _sizeLetter ,
b . _localId ,
b . _volumeId ,
b . _dcId ) ;
case Type : : StickerSetThumb :
return std : : tie ( a . _id , a . _localId , a . _volumeId , a . _dcId )
< std : : tie ( b . _id , b . _localId , b . _volumeId , b . _dcId ) ;
} ;
Unexpected ( " Type in StorageFileLocation::operator==. " ) ;
}
2019-03-22 14:19:43 +00:00
InMemoryKey inMemoryKey ( const StorageFileLocation & location ) {
const auto key = location . cacheKey ( ) ;
return { key . high , key . low } ;
}
2018-10-23 09:44:42 +00:00
StorageImageLocation : : StorageImageLocation (
2019-03-22 13:43:34 +00:00
const StorageFileLocation & file ,
int width ,
int height )
: _file ( file )
, _width ( width )
, _height ( height ) {
2018-10-23 09:44:42 +00:00
}
2019-03-22 14:19:43 +00:00
QByteArray StorageImageLocation : : serialize ( ) const {
auto result = _file . serialize ( ) ;
if ( ! result . isEmpty ( ) | | ( _width > 0 ) | | ( _height > 0 ) ) {
result . reserve ( result . size ( ) + 2 * sizeof ( qint32 ) ) ;
auto buffer = QBuffer ( & result ) ;
buffer . open ( QIODevice : : Append ) ;
auto stream = QDataStream ( & buffer ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream < < qint32 ( _width ) < < qint32 ( _height ) ;
}
return result ;
}
int StorageImageLocation : : serializeSize ( ) const {
const auto partial = _file . serializeSize ( ) ;
return ( partial > 0 | | _width > 0 | | _height > 0 )
? ( partial + 2 * sizeof ( qint32 ) )
: 0 ;
}
std : : optional < StorageImageLocation > StorageImageLocation : : FromSerialized (
const QByteArray & serialized ) {
if ( const auto file = StorageFileLocation : : FromSerialized ( serialized ) ) {
const auto my = 2 * sizeof ( qint32 ) ;
const auto full = serialized . size ( ) ;
if ( ! full ) {
return StorageImageLocation ( * file , 0 , 0 ) ;
} else if ( full > = my ) {
qint32 width = 0 ;
qint32 height = 0 ;
const auto dimensions = QByteArray : : fromRawData (
serialized . data ( ) + full - my , my ) ;
auto stream = QDataStream ( dimensions ) ;
stream . setVersion ( QDataStream : : Qt_5_1 ) ;
stream > > width > > height ;
return ( stream . status ( ) = = QDataStream : : Ok )
? StorageImageLocation ( * file , width , height )
: std : : optional < StorageImageLocation > ( ) ;
}
}
return std : : nullopt ;
}
2018-10-23 09:44:42 +00:00
ReadAccessEnabler : : ReadAccessEnabler ( const PsFileBookmark * bookmark )
: _bookmark ( bookmark )
, _failed ( _bookmark ? ! _bookmark - > enable ( ) : false ) {
}
ReadAccessEnabler : : ReadAccessEnabler (
const std : : shared_ptr < PsFileBookmark > & bookmark )
: _bookmark ( bookmark . get ( ) )
, _failed ( _bookmark ? ! _bookmark - > enable ( ) : false ) {
}
ReadAccessEnabler : : ~ ReadAccessEnabler ( ) {
if ( _bookmark & & ! _failed ) _bookmark - > disable ( ) ;
}
FileLocation : : FileLocation ( const QString & name ) : fname ( name ) {
2019-05-31 16:45:03 +00:00
if ( fname . isEmpty ( ) | | fname = = kInMediaCacheLocation ) {
2018-10-23 09:44:42 +00:00
size = 0 ;
} else {
setBookmark ( psPathBookmark ( name ) ) ;
QFileInfo f ( name ) ;
if ( f . exists ( ) ) {
qint64 s = f . size ( ) ;
if ( s > INT_MAX ) {
fname = QString ( ) ;
_bookmark = nullptr ;
size = 0 ;
} else {
modified = f . lastModified ( ) ;
size = qint32 ( s ) ;
}
} else {
fname = QString ( ) ;
_bookmark = nullptr ;
size = 0 ;
}
}
}
2019-05-31 16:45:03 +00:00
FileLocation FileLocation : : InMediaCacheLocation ( ) {
return FileLocation ( kInMediaCacheLocation ) ;
}
2018-10-23 09:44:42 +00:00
bool FileLocation : : check ( ) const {
2019-05-31 16:45:03 +00:00
if ( fname . isEmpty ( ) | | fname = = kInMediaCacheLocation ) {
return false ;
}
2018-10-23 09:44:42 +00:00
ReadAccessEnabler enabler ( _bookmark ) ;
if ( enabler . failed ( ) ) {
const_cast < FileLocation * > ( this ) - > _bookmark = nullptr ;
}
QFileInfo f ( name ( ) ) ;
if ( ! f . isReadable ( ) ) return false ;
quint64 s = f . size ( ) ;
if ( s > INT_MAX ) {
DEBUG_LOG ( ( " File location check: Wrong size %1 " ) . arg ( s ) ) ;
return false ;
}
if ( qint32 ( s ) ! = size ) {
DEBUG_LOG ( ( " File location check: Wrong size %1 when should be %2 " ) . arg ( s ) . arg ( size ) ) ;
return false ;
}
auto realModified = f . lastModified ( ) ;
if ( realModified ! = modified ) {
DEBUG_LOG ( ( " File location check: Wrong last modified time %1 when should be %2 " ) . arg ( realModified . toMSecsSinceEpoch ( ) ) . arg ( modified . toMSecsSinceEpoch ( ) ) ) ;
return false ;
}
return true ;
}
const QString & FileLocation : : name ( ) const {
return _bookmark ? _bookmark - > name ( fname ) : fname ;
}
QByteArray FileLocation : : bookmark ( ) const {
return _bookmark ? _bookmark - > bookmark ( ) : QByteArray ( ) ;
}
2019-05-31 16:45:03 +00:00
bool FileLocation : : inMediaCache ( ) const {
return ( fname = = kInMediaCacheLocation ) ;
}
2018-10-23 09:44:42 +00:00
void FileLocation : : setBookmark ( const QByteArray & bm ) {
_bookmark . reset ( bm . isEmpty ( ) ? nullptr : new PsFileBookmark ( bm ) ) ;
}
bool FileLocation : : accessEnable ( ) const {
return isEmpty ( ) ? false : ( _bookmark ? _bookmark - > enable ( ) : true ) ;
}
void FileLocation : : accessDisable ( ) const {
return _bookmark ? _bookmark - > disable ( ) : ( void ) 0 ;
}