From cd57194072c7149b3b1994bec3fe7e5232508e77 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Sat, 14 Aug 2021 15:49:52 +0200 Subject: [PATCH] Update --- .github/workflows/main.yml | 2 +- src/FileId.php | 53 ++++-- src/PhotoSizeSource.php | 6 +- .../PhotoSizeSourceDialogPhoto.php | 23 +-- src/PhotoSizeSource/PhotoSizeSourceLegacy.php | 9 - .../PhotoSizeSourceStickersetThumbnail.php | 9 - ...toSizeSourceStickersetThumbnailVersion.php | 121 ++++++++++++ .../PhotoSizeSourceThumbnail.php | 8 - src/UniqueFileId.php | 177 +++++++++++++++++- src/type.php | 117 +++++++++--- 10 files changed, 427 insertions(+), 98 deletions(-) create mode 100644 src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnailVersion.php diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab58584..642004d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: tag: ["amd64"] - php: ["7.0", "7.1", "7.2", "7.3", "7.4"] + php: ["7.0", "7.1", "7.2", "7.3", "7.4", "8.0"] name: PHP ${{ matrix.php }} Test on ${{ matrix.tag }} steps: - name: Checkout diff --git a/src/FileId.php b/src/FileId.php index 91d5d41..79acc48 100644 --- a/src/FileId.php +++ b/src/FileId.php @@ -21,6 +21,7 @@ namespace danog\Decoder; use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhoto; use danog\Decoder\PhotoSizeSource\PhotoSizeSourceLegacy; use danog\Decoder\PhotoSizeSource\PhotoSizeSourceStickersetThumbnail; +use danog\Decoder\PhotoSizeSource\PhotoSizeSourceStickersetThumbnailVersion; use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail; /** @@ -137,30 +138,43 @@ class FileId $result->setId($resultArray['id']); if ($result->getType() <= PHOTO) { - $result->setVolumeId($resultArray['volume_id']); - $result->setLocalId($resultArray['local_id']); + if (isset($resultArray['volume_id'])) { + $result->setVolumeId($resultArray['volume_id']); + } + if (isset($resultArray['local_id'])) { + $result->setLocalId($resultArray['local_id']); + } switch ($resultArray['photosize_source']) { case PHOTOSIZE_SOURCE_LEGACY: - $photoSizeSource = new PhotoSizeSourceLegacy; + case PHOTOSIZE_SOURCE_FULL_LEGACY: + $photoSizeSource = new PhotoSizeSourceLegacy($resultArray['photosize_source']); $photoSizeSource->setSecret($resultArray['secret']); break; case PHOTOSIZE_SOURCE_THUMBNAIL: - $photoSizeSource = new PhotoSizeSourceThumbnail; + $photoSizeSource = new PhotoSizeSourceThumbnail($resultArray['photosize_source']); $photoSizeSource->setThumbType($resultArray['thumbnail_type']); $photoSizeSource->setThumbFileType($resultArray['file_type']); break; - case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG_LEGACY: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY: case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG: - $photoSizeSource = new PhotoSizeSourceDialogPhoto; - $photoSizeSource->setDialogPhotoSmall($resultArray['photosize_source'] === PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL); + case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL: + $photoSizeSource = new PhotoSizeSourceDialogPhoto($resultArray['photosize_source']); $photoSizeSource->setDialogId($resultArray['dialog_id']); $photoSizeSource->setDialogAccessHash($resultArray['dialog_access_hash']); break; case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL: - $photoSizeSource = new PhotoSizeSourceStickersetThumbnail; + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY: + $photoSizeSource = new PhotoSizeSourceStickersetThumbnail($resultArray['photosize_source']); $photoSizeSource->setStickerSetId($resultArray['sticker_set_id']); $photoSizeSource->setStickerSetAccessHash($resultArray['sticker_set_access_hash']); break; + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION: + $photoSizeSource = new PhotoSizeSourceStickersetThumbnailVersion($resultArray['photosize_source']); + $photoSizeSource->setStickerSetId($resultArray['sticker_set_id']); + $photoSizeSource->setStickerSetAccessHash($resultArray['sticker_set_access_hash']); + $photoSizeSource->setStickerSetVersion($resultArray['sticker_version']); + break; } $result->setPhotoSizeSource($photoSizeSource); } @@ -198,29 +212,42 @@ class FileId $fileId .= packLong($this->getAccessHash()); if ($this->getType() <= PHOTO) { - $fileId .= packLong($this->getVolumeId()); $photoSize = $this->getPhotoSizeSource(); - if ($this->getVersion() >= 4) { - $fileId .= \pack('V', $photoSize->getType()); - } + $fileId .= \pack('V', $photoSize->getType()); switch ($photoSize->getType()) { case PHOTOSIZE_SOURCE_LEGACY: $fileId .= packLong($photoSize->getSecret()); break; + case PHOTOSIZE_SOURCE_FULL_LEGACY: + $fileId .= packLong($this->getVolumeId()); + $fileId .= packLong($photoSize->getSecret()); + $fileId .= pack('l',$this->getLocalId()); + break; case PHOTOSIZE_SOURCE_THUMBNAIL: $fileId .= \pack('Va4', $photoSize->getThumbFileType(), $photoSize->getThumbType()); break; case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG: case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG_LEGACY: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY: $fileId .= packLongBig($photoSize->getDialogId()); $fileId .= packLong($photoSize->getDialogAccessHash()); break; case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL: + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY: $fileId .= packLong($photoSize->getStickerSetId()); $fileId .= packLong($photoSize->getStickerSetAccessHash()); break; + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION: + $fileId .= packLong($photoSize->getStickerSetId()); + $fileId .= packLong($photoSize->getStickerSetAccessHash()); + $fileId .= pack('l', $photoSize->getStickerSetVersion()); + break; + } + if ($photoSize->getType() >= PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY && $photoSize->getType() <= PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY) { + $fileId .= packLong($this->getVolumeId()); + $fileId .= \pack('l', $this->getLocalId()); } - $fileId .= \pack('l', $this->getLocalId()); } if ($this->getVersion() >= 4) { diff --git a/src/PhotoSizeSource.php b/src/PhotoSizeSource.php index cef92fc..f819dfd 100644 --- a/src/PhotoSizeSource.php +++ b/src/PhotoSizeSource.php @@ -35,13 +35,11 @@ abstract class PhotoSizeSource private $_type; /** - * Get photosize source type. + * Set photosize source type. * * @param integer $type Type - * - * @return self */ - public function setType(int $type): self + public function __construct(int $type) { $this->_type = $type; diff --git a/src/PhotoSizeSource/PhotoSizeSourceDialogPhoto.php b/src/PhotoSizeSource/PhotoSizeSourceDialogPhoto.php index 1302e28..7614ea9 100644 --- a/src/PhotoSizeSource/PhotoSizeSourceDialogPhoto.php +++ b/src/PhotoSizeSource/PhotoSizeSourceDialogPhoto.php @@ -22,6 +22,7 @@ use danog\Decoder\PhotoSizeSource; use const danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG; use const danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL; +use const danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY; /** * Represents source of photosize. @@ -43,14 +44,6 @@ class PhotoSizeSourceDialogPhoto extends PhotoSizeSource */ private $_dialogAccessHash; - /** - * Constructor. - */ - public function __construct() - { - $this->setType(PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG); - } - /** * Get dialog ID. * @@ -103,18 +96,6 @@ class PhotoSizeSourceDialogPhoto extends PhotoSizeSource */ public function isSmallDialogPhoto(): bool { - return $this->getType() === PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL; - } - - /** - * Set whether the big or small version of the photo is being used. - * - * @param bool $_dialogPhotoSmall Whether the big or small version of the photo is being used - * - * @return self - */ - public function setDialogPhotoSmall(bool $_dialogPhotoSmall): self - { - return $this->setType($_dialogPhotoSmall ? PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL : PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG); + return in_array($this->getType(), [PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY, PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL]); } } diff --git a/src/PhotoSizeSource/PhotoSizeSourceLegacy.php b/src/PhotoSizeSource/PhotoSizeSourceLegacy.php index 8a1b37a..c23dd22 100644 --- a/src/PhotoSizeSource/PhotoSizeSourceLegacy.php +++ b/src/PhotoSizeSource/PhotoSizeSourceLegacy.php @@ -20,8 +20,6 @@ namespace danog\Decoder\PhotoSizeSource; use danog\Decoder\PhotoSizeSource; -use const danog\Decoder\PHOTOSIZE_SOURCE_LEGACY; - /** * Represents source of photosize. * @@ -29,13 +27,6 @@ use const danog\Decoder\PHOTOSIZE_SOURCE_LEGACY; */ class PhotoSizeSourceLegacy extends PhotoSizeSource { - /** - * Constructor. - */ - public function __construct() - { - $this->setType(PHOTOSIZE_SOURCE_LEGACY); - } /** * Secret legacy ID. * diff --git a/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnail.php b/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnail.php index 30b4964..5069b3d 100644 --- a/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnail.php +++ b/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnail.php @@ -20,8 +20,6 @@ namespace danog\Decoder\PhotoSizeSource; use danog\Decoder\PhotoSizeSource; -use const danog\Decoder\PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL; - /** * Represents source of photosize. * @@ -29,13 +27,6 @@ use const danog\Decoder\PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL; */ class PhotoSizeSourceStickersetThumbnail extends PhotoSizeSource { - /** - * Constructor. - */ - public function __construct() - { - $this->setType(PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL); - } /** * Stickerset ID. * diff --git a/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnailVersion.php b/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnailVersion.php new file mode 100644 index 0000000..f230074 --- /dev/null +++ b/src/PhotoSizeSource/PhotoSizeSourceStickersetThumbnailVersion.php @@ -0,0 +1,121 @@ +. + * + * @author Daniil Gentili + * @copyright 2016-2019 Daniil Gentili + * @license https://opensource.org/licenses/AGPL-3.0 AGPLv3 + * + * @link https://github.com/tg-file-decoder Documentation + */ + +namespace danog\Decoder\PhotoSizeSource; + +use danog\Decoder\PhotoSizeSource; + +/** + * Represents source of photosize. + * + * @extends PhotoSizeSource + */ +class PhotoSizeSourceStickersetThumbnailVersion extends PhotoSizeSource +{ + /** + * Stickerset ID. + * + * @var int + */ + private $_stickerSetId; + /** + * Stickerset access hash. + * + * @var int + */ + private $_stickerSetAccessHash; + /** + * Stickerset version. + * + * @var int + */ + private $_stickerSetVersion; + + + /** + * Get stickerset ID. + * + * @return int + */ + public function getStickerSetId() + { + return $this->_stickerSetId; + } + + /** + * Set stickerset ID. + * + * @param int $_stickerSetId Stickerset ID + * + * @return self + */ + public function setStickerSetId($_stickerSetId): self + { + $this->_stickerSetId = $_stickerSetId; + + return $this; + } + + /** + * Get stickerset access hash. + * + * @return int + */ + public function getStickerSetAccessHash() + { + return $this->_stickerSetAccessHash; + } + + /** + * Set stickerset access hash. + * + * @param int $_stickerSetAccessHash Stickerset access hash + * + * @return self + */ + public function setStickerSetAccessHash($_stickerSetAccessHash): self + { + $this->_stickerSetAccessHash = $_stickerSetAccessHash; + + return $this; + } + + /** + * Get stickerset version. + * + * @return int + */ + public function getStickerSetVersion(): int + { + return $this->_stickerSetVersion; + } + + /** + * Set stickerset version. + * + * @param int $_stickerSetVersion Stickerset version. + * + * @return self + */ + public function setStickerSetVersion(int $_stickerSetVersion): self + { + $this->_stickerSetVersion = $_stickerSetVersion; + + return $this; + } +} diff --git a/src/PhotoSizeSource/PhotoSizeSourceThumbnail.php b/src/PhotoSizeSource/PhotoSizeSourceThumbnail.php index 29cc0eb..75453aa 100644 --- a/src/PhotoSizeSource/PhotoSizeSourceThumbnail.php +++ b/src/PhotoSizeSource/PhotoSizeSourceThumbnail.php @@ -20,7 +20,6 @@ namespace danog\Decoder\PhotoSizeSource; use danog\Decoder\PhotoSizeSource; -use const danog\Decoder\PHOTOSIZE_SOURCE_THUMBNAIL; use const danog\Decoder\TYPES; /** @@ -28,13 +27,6 @@ use const danog\Decoder\TYPES; */ class PhotoSizeSourceThumbnail extends PhotoSizeSource { - /** - * Constructor. - */ - public function __construct() - { - $this->setType(PHOTOSIZE_SOURCE_THUMBNAIL); - } /** * File type of original file. * diff --git a/src/UniqueFileId.php b/src/UniqueFileId.php index 5a85dc1..909e806 100644 --- a/src/UniqueFileId.php +++ b/src/UniqueFileId.php @@ -18,6 +18,10 @@ namespace danog\Decoder; +use danog\Decoder\PhotoSizeSource\PhotoSizeSourceDialogPhoto; +use danog\Decoder\PhotoSizeSource\PhotoSizeSourceStickersetThumbnailVersion; +use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail; + /** * Represents decoded unique bot API file ID. */ @@ -47,6 +51,24 @@ class UniqueFileId * @var int */ private $_localId; + /** + * Photo subtype + * + * @var int + */ + private $_subType; + /** + * Sticker set ID + * + * @var int + */ + private $_stickerSetId; + /** + * Sticker set version + * + * @var int + */ + private $_stickerSetVersion; /** * Weblocation URL. * @@ -81,8 +103,17 @@ class UniqueFileId if ($this->getType() === UNIQUE_WEB) { $fileId .= packTLString($this->getUrl()); } elseif ($this->getType() === UNIQUE_PHOTO) { - $fileId .= packLong($this->getVolumeId()); - $fileId .= \pack('l', $this->getLocalId()); + if ($this->hasVolumeId()) { + $fileId .= packLong($this->getVolumeId()); + $fileId .= \pack('l', $this->getLocalId()); + } elseif ($this->hasStickerSetId()) { + $fileId .= chr($this->getSubType()); + $fileId .= packLong($this->getStickerSetId()); + $fileId .= pack('l', $this->getStickerSetVersion()); + } else { + $fileId .= packLong($this->getId()); + $fileId .= chr($this->getSubType()); + } } elseif ($this->hasId()) { $fileId .= packLong($this->getId()); } @@ -105,8 +136,17 @@ class UniqueFileId if ($result->getType() === UNIQUE_WEB) { $result->setUrl($resultArray['url']); } elseif ($result->getType() === UNIQUE_PHOTO) { - $result->setVolumeId($resultArray['volume_id']); - $result->setLocalId($resultArray['local_id']); + if (isset($resultArray['volume_id'])) { + $result->setVolumeId($resultArray['volume_id']); + $result->setLocalId($resultArray['local_id']); + } else if (isset($resultArray['id'])) { + $result->setId($resultArray['id']); + $result->setSubType($resultArray['subType']); + } else if (isset($resultArray['sticker_set_id'])) { + $result->setStickerSetId($resultArray['sticker_set_id']); + $result->setStickerSetVersion($resultArray['sticker_set_version']); + $result->setSubType($resultArray['subType']); + } } elseif (isset($resultArray['id'])) { $result->setId($resultArray['id']); } @@ -143,8 +183,30 @@ class UniqueFileId if ($result->getType() === UNIQUE_WEB) { $result->setUrl($fileId->getUrl()); } elseif ($result->getType() === UNIQUE_PHOTO) { - $result->setVolumeId($fileId->getVolumeId()); - $result->setLocalId($fileId->getLocalId()); + if ($fileId->hasVolumeId()) { + $result->setVolumeId($fileId->getVolumeId()); + $result->setLocalId($fileId->getLocalId()); + } else if ($fileId->hasId()) { + $result->setId($fileId->getId()); + $photoSize = $fileId->getPhotoSizeSource(); + if ($photoSize instanceof PhotoSizeSourceThumbnail) { + $type = $photoSize->getThumbType(); + if ($type === 'a') { + $type = chr(0); + } else if ($type === 'c') { + $type = chr(1); + } else { + $type = chr(ord($type)+5); + } + $result->setSubType(ord($type)); + } else if ($photoSize instanceof PhotoSizeSourceDialogPhoto) { + $result->setSubType($photoSize->isSmallDialogPhoto() ? 0 : 1); + } else if ($photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion) { + $result->setSubType(2); + $result->setStickerSetId($photoSize->getStickerSetId()); + $result->setStickerSetVersion($photoSize->getStickerSetVersion()); + } + } } elseif ($fileId->hasId()) { $result->setId($fileId->getId()); } @@ -322,4 +384,107 @@ class UniqueFileId { return isset($this->_url); } + + /** + * Get photo subtype + * + * @return int + */ + public function getSubType(): int + { + return $this->_subType; + } + + /** + * Has photo subtype? + * + * @return bool + */ + public function hasSubType(): bool + { + return isset($this->_subType); + } + + /** + * Set photo subtype + * + * @param int $_subType Photo subtype + * + * @return self + */ + public function setSubType(int $_subType): self + { + $this->_subType = $_subType; + + return $this; + } + + /** + * Get sticker set ID + * + * @return int + */ + public function getStickerSetId() + { + return $this->_stickerSetId; + } + + + /** + * Has sticker set ID? + * + * @return bool + */ + public function hasStickerSetId(): bool + { + return isset($this->_stickerSetId); + } + + /** + * Set sticker set ID + * + * @param int $_stickerSetId Sticker set ID + * + * @return self + */ + public function setStickerSetId($_stickerSetId): self + { + $this->_stickerSetId = $_stickerSetId; + + return $this; + } + + /** + * Get sticker set version + * + * @return int + */ + public function getStickerSetVersion(): int + { + return $this->_stickerSetVersion; + } + + /** + * Has sticker set version + * + * @return bool + */ + public function hasStickerSetVersion(): bool + { + return isset($this->_stickerSetVersion); + } + + /** + * Set sticker set version + * + * @param int $_stickerSetVersion Sticker set version + * + * @return self + */ + public function setStickerSetVersion(int $_stickerSetVersion): self + { + $this->_stickerSetVersion = $_stickerSetVersion; + + return $this; + } } diff --git a/src/type.php b/src/type.php index 86e9a13..1be67fc 100644 --- a/src/type.php +++ b/src/type.php @@ -189,6 +189,11 @@ const PHOTOSIZE_SOURCE_THUMBNAIL = 1; const PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL = 2; const PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG = 3; const PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL = 4; +const PHOTOSIZE_SOURCE_FULL_LEGACY = 5; +const PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY = 6; +const PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG_LEGACY = 7; +const PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY = 8; +const PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION = 9; const WEB_LOCATION_FLAG = 1 << 24; const FILE_REFERENCE_FLAG = 1 << 25; @@ -492,33 +497,75 @@ function internalDecode(string $fileId): array fixLong($result, 'access_hash'); if ($result['typeId'] <= PHOTO) { - $result += \unpack(LONG.'volume_id', \stream_get_contents($fileId, 8)); - fixLong($result, 'volume_id'); - $result['secret'] = 0; - $result['photosize_source'] = $result['version'] >= 4 ? \unpack('V', \stream_get_contents($fileId, 4))[1] : 0; - // Legacy, Thumbnail, DialogPhotoSmall, DialogPhotoBig, StickerSetThumbnail - switch ($result['photosize_source']) { - case PHOTOSIZE_SOURCE_LEGACY: - $result += \unpack(LONG.'secret', \stream_get_contents($fileId, 8)); + $parsePhotoSize = function () use (&$result, &$fileId): void { + $result['photosize_source'] = $result['subVersion'] >= 4 ? \unpack('V', \stream_get_contents($fileId, 4))[1] : 0; + switch ($result['photosize_source']) { + case PHOTOSIZE_SOURCE_LEGACY: + $result += \unpack(LONG.'secret', \stream_get_contents($fileId, 8)); + fixLong($result, 'secret'); + break; + case PHOTOSIZE_SOURCE_THUMBNAIL: + $result += \unpack('Vfile_type/athumbnail_type', \stream_get_contents($fileId, 8)); + break; + case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL: + $result['photo_size'] = $result['photosize_source'] === PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL ? 'photo_small' : 'photo_big'; + $result['dialog_id'] = unpackLong(\stream_get_contents($fileId, 8)); + $result['dialog_access_hash'] = \unpack(LONG, \stream_get_contents($fileId, 8))[1]; + fixLong($result, 'dialog_access_hash'); + break; + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL: + $result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash', \stream_get_contents($fileId, 16)); + fixLong($result, 'sticker_set_id'); + fixLong($result, 'sticker_set_access_hash'); + break; + + case PHOTOSIZE_SOURCE_FULL_LEGACY: + $result += \unpack(LONG.'volume_id/'.LONG.'secret/llocal_id', \stream_get_contents($fileId, 20)); + fixLong($result, 'volume_id'); + fixLong($result, 'secret'); + break; + case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG_LEGACY: + case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY: + $result['photo_size'] = $result['photosize_source'] === PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY ? 'photo_small' : 'photo_big'; + $result['dialog_id'] = unpackLong(\stream_get_contents($fileId, 8)); + $result['dialog_access_hash'] = \unpack(LONG, \stream_get_contents($fileId, 8))[1]; + fixLong($result, 'dialog_access_hash'); + + $result += \unpack(LONG.'volume_id/llocal_id', \stream_get_contents($fileId, 12)); + fixLong($result, 'volume_id'); + break; + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY: + $result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash', \stream_get_contents($fileId, 16)); + fixLong($result, 'sticker_set_id'); + fixLong($result, 'sticker_set_access_hash'); + + $result += \unpack(LONG.'volume_id/llocal_id', \stream_get_contents($fileId, 12)); + fixLong($result, 'volume_id'); + break; + + case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION: + $result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash/lsticker_version', \stream_get_contents($fileId, 20)); + fixLong($result, 'sticker_set_id'); + fixLong($result, 'sticker_set_access_hash'); + break; + } + }; + if ($result['subVersion'] >= 32) { + $parsePhotoSize(); + } else { + $result += \unpack(LONG.'volume_id', \stream_get_contents($fileId, 8)); + fixLong($result, 'volume_id'); + + if ($result['subVersion'] >= 22) { + $parsePhotoSize(); + $result += \unpack('llocal_id', \stream_get_contents($fileId, 4)); + } else { + $result += \unpack(LONG.'secret/llocal_id', \stream_get_contents($fileId, 12)); + fixLong($result, 'volume_id'); fixLong($result, 'secret'); - break; - case PHOTOSIZE_SOURCE_THUMBNAIL: - $result += \unpack('Vfile_type/athumbnail_type', \stream_get_contents($fileId, 8)); - break; - case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG: - case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL: - $result['photo_size'] = $result['photosize_source'] === PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL ? 'photo_small' : 'photo_big'; - $result['dialog_id'] = unpackLong(\stream_get_contents($fileId, 8)); - $result['dialog_access_hash'] = \unpack(LONG, \stream_get_contents($fileId, 8))[1]; - fixLong($result, 'dialog_access_hash'); - break; - case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL: - $result += \unpack(LONG.'sticker_set_id/'.LONG.'sticker_set_access_hash', \stream_get_contents($fileId, 16)); - fixLong($result, 'sticker_set_id'); - fixLong($result, 'sticker_set_access_hash'); - break; + } } - $result += \unpack('llocal_id', \stream_get_contents($fileId, 4)); } $l = \fstat($fileId)['size'] - \ftell($fileId); $l -= $result['version'] >= 4 ? 2 : 1; @@ -560,15 +607,31 @@ function internalDecodeUnique(string $fileId): array $l = \fstat($fileId)['size'] - \ftell($fileId); } elseif (\strlen($fileId) === 12) { + // Legacy photos $result += \unpack(LONG.'volume_id/llocal_id', $fileId); fixLong($result, 'volume_id'); $l = 0; - } else { + } elseif (\strlen($fileId) === 9) { + // Dialog photos/thumbnails + $result += \unpack(LONG.'id/CsubType', $fileId); + fixLong($result, 'id'); + + $l = 0; + } elseif (\strlen($fileId) === 13) { + // Stickerset ID/version + $result += \unpack('CsubType/'.LONG.'sticker_set_id/lsticker_set_version', $fileId); + fixLong($result, 'sticker_set_id'); + + $l = 0; + } elseif (\strlen($fileId) === 8) { + // Any other document $result += \unpack(LONG.'id', $fileId); fixLong($result, 'id'); - $l = \strlen($fileId) - 8; + $l = 0; + } else { + $l = strlen($fileId); } if ($l > 0) { \trigger_error("Unique file ID $orig has $l bytes of leftover data");