Modernize

This commit is contained in:
Daniil Gentili 2024-04-01 15:02:20 +02:00
parent 500f131d85
commit 464800a3c5
16 changed files with 313 additions and 314 deletions

View File

@ -44,5 +44,6 @@ jobs:
TOKEN: ${{ secrets.TOKEN }}
DEST: ${{ secrets.DEST }}
run: |
vendor/bin/psalm --no-cache
vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
vendor/bin/php-cs-fixer --diff --dry-run -v fix

View File

@ -15,14 +15,15 @@
},
"require-dev": {
"phpunit/phpunit": "^9",
"amphp/php-cs-fixer-config": "^2"
"amphp/php-cs-fixer-config": "^2",
"vimeo/psalm": "dev-master"
},
"autoload": {
"psr-4": {
"danog\\Decoder\\": "src/"
},
"files": [
"src/type.php"
"src/functions.php"
]
},
"autoload-dev": {

8
psalm-baseline.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="dev-master@ef3b018e89c4ffc157332c13e2ebf9cf22320d17">
<file src="src/functions.php">
<UnusedVariable>
<code><![CDATA[$BIG_ENDIAN]]></code>
</UnusedVariable>
</file>
</files>

View File

@ -5,6 +5,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorBaseline="psalm-baseline.xml"
>
<projectFiles>
<directory name="src" />

View File

@ -26,8 +26,10 @@ use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail;
/**
* Represents decoded bot API file ID.
*
* @api
*/
class FileId
final class FileId
{
/**
* Bot API file ID version.
@ -51,7 +53,7 @@ class FileId
* File type.
*
*/
private int $type = 0;
private FileIdType $type = FileIdType::NONE;
/**
* File reference.
@ -123,7 +125,7 @@ class FileId
}
$result->setId($resultArray['id']);
if ($result->getType() <= PHOTO) {
if ($result->getType()->value <= FileIdType::PHOTO->value) {
if (isset($resultArray['volume_id'])) {
$result->setVolumeId($resultArray['volume_id']);
}
@ -131,31 +133,31 @@ class FileId
$result->setLocalId($resultArray['local_id']);
}
switch ($resultArray['photosize_source']) {
case PHOTOSIZE_SOURCE_LEGACY:
case PHOTOSIZE_SOURCE_FULL_LEGACY:
case PhotoSizeSourceType::LEGACY:
case PhotoSizeSourceType::FULL_LEGACY:
$photoSizeSource = new PhotoSizeSourceLegacy($resultArray['photosize_source']);
$photoSizeSource->setSecret($resultArray['secret']);
break;
case PHOTOSIZE_SOURCE_THUMBNAIL:
case PhotoSizeSourceType::THUMBNAIL:
$photoSizeSource = new PhotoSizeSourceThumbnail($resultArray['photosize_source']);
$photoSizeSource->setThumbType($resultArray['thumbnail_type']);
$photoSizeSource->setThumbFileType($resultArray['file_type']);
break;
case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG_LEGACY:
case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY:
case PHOTOSIZE_SOURCE_DIALOGPHOTO_BIG:
case PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL:
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
case PhotoSizeSourceType::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:
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY:
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
case PhotoSizeSourceType::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:
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_VERSION:
$photoSizeSource = new PhotoSizeSourceStickersetThumbnailVersion($resultArray['photosize_source']);
$photoSizeSource->setStickerSetId($resultArray['sticker_set_id']);
$photoSizeSource->setStickerSetAccessHash($resultArray['sticker_set_access_hash']);
@ -174,7 +176,7 @@ class FileId
*/
public function getBotAPI(): string
{
$type = $this->getType();
$type = $this->getType()->value;
if ($this->hasFileReference()) {
$type |= FILE_REFERENCE_FLAG;
}
@ -195,40 +197,46 @@ class FileId
$fileId .= packLong($this->getId());
$fileId .= packLong($this->getAccessHash());
if ($this->getType() <= PHOTO) {
if ($this->getType()->value <= FileIdType::PHOTO->value) {
$photoSize = $this->getPhotoSizeSource();
$fileId .= \pack('V', $photoSize->getType());
switch ($photoSize->getType()) {
case PHOTOSIZE_SOURCE_LEGACY:
case PhotoSizeSourceType::LEGACY:
assert($photoSize instanceof PhotoSizeSourceLegacy);
$fileId .= packLong($photoSize->getSecret());
break;
case PHOTOSIZE_SOURCE_FULL_LEGACY:
case PhotoSizeSourceType::FULL_LEGACY:
assert($photoSize instanceof PhotoSizeSourceLegacy);
$fileId .= packLong($this->getVolumeId());
$fileId .= packLong($photoSize->getSecret());
$fileId .= \pack('l', $this->getLocalId());
break;
case PHOTOSIZE_SOURCE_THUMBNAIL:
case PhotoSizeSourceType::THUMBNAIL:
assert($photoSize instanceof PhotoSizeSourceThumbnail);
$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:
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
assert($photoSize instanceof PhotoSizeSourceDialogPhoto);
$fileId .= packLongBig($photoSize->getDialogId());
$fileId .= packLong($photoSize->getDialogAccessHash());
break;
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL:
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY:
case PhotoSizeSourceType::STICKERSET_THUMBNAIL:
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY:
assert($photoSize instanceof PhotoSizeSourceStickersetThumbnail);
$fileId .= packLong($photoSize->getStickerSetId());
$fileId .= packLong($photoSize->getStickerSetAccessHash());
break;
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION:
case PhotoSizeSourceType::STICKERSET_THUMBNAIL_VERSION:
assert($photoSize instanceof PhotoSizeSourceStickersetThumbnailVersion);
$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) {
if ($photoSize->getType() >= PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY && $photoSize->getType()->value <= PhotoSizeSourceType::STICKERSET_THUMBNAIL_LEGACY->value) {
$fileId .= packLong($this->getVolumeId());
$fileId .= \pack('l', $this->getLocalId());
}
@ -314,27 +322,18 @@ class FileId
* Get file type.
*
*/
public function getType(): int
public function getType(): FileIdType
{
return $this->type;
}
/**
* Get file type as string.
*
*/
public function getTypeName(): string
{
return TYPES[$this->type];
}
/**
* Set file type.
*
* @param int $type File type.
* @param FileIdType $type File type.
*
*/
public function setType(int $type): self
public function setType(FileIdType $type): self
{
$this->type = $type;

132
src/FileIdType.php Normal file
View File

@ -0,0 +1,132 @@
<?php declare(strict_types=1);
/**
* Type enum + helper functions.
*
* This file is part of tg-file-decoder.
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* tg-file-decoder 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 Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://github.com/tg-file-decoder Documentation
*/
namespace danog\Decoder;
use AssertionError;
enum FileIdType: int
{
/**
* Thumbnail.
*/
case THUMBNAIL = 0;
/**
* Profile photo.
* Used for users and channels, chat photos are normal PHOTOs.
*/
case PROFILE_PHOTO = 1;
/**
* Normal photos.
*/
case PHOTO = 2;
/**
* Voice messages.
*/
case VOICE = 3;
/**
* Video.
*/
case VIDEO = 4;
/**
* Document.
*/
case DOCUMENT = 5;
/**
* Secret chat document.
*/
case ENCRYPTED = 6;
/**
* Temporary document.
*/
case TEMP = 7;
/**
* Sticker.
*/
case STICKER = 8;
/**
* Music.
*/
case AUDIO = 9;
/**
* GIF.
*/
case ANIMATION = 10;
/**
* Encrypted thumbnail.
*/
case ENCRYPTED_THUMBNAIL = 11;
/**
* Wallpaper.
*/
case WALLPAPER = 12;
/**
* Round video.
*/
case VIDEO_NOTE = 13;
/**
* Passport raw file.
*/
case SECURE_RAW = 14;
/**
* Passport file.
*/
case SECURE = 15;
/**
* Background.
*/
case BACKGROUND = 16;
/**
* Size.
*/
case SIZE = 17;
case NONE = 18;
/**
* Convert file ID type to unique file ID type.
*/
public function toUnique(): UniqueFileIdType
{
return match ($this) {
self::PHOTO => UniqueFileIdType::PHOTO,
self::PROFILE_PHOTO => UniqueFileIdType::PHOTO,
self::THUMBNAIL => UniqueFileIdType::PHOTO,
self::ENCRYPTED_THUMBNAIL => UniqueFileIdType::PHOTO,
self::WALLPAPER => UniqueFileIdType::PHOTO,
self::VIDEO => UniqueFileIdType::DOCUMENT,
self::VOICE => UniqueFileIdType::DOCUMENT,
self::DOCUMENT => UniqueFileIdType::DOCUMENT,
self::STICKER => UniqueFileIdType::DOCUMENT,
self::AUDIO => UniqueFileIdType::DOCUMENT,
self::ANIMATION => UniqueFileIdType::DOCUMENT,
self::VIDEO_NOTE => UniqueFileIdType::DOCUMENT,
self::BACKGROUND => UniqueFileIdType::DOCUMENT,
self::SECURE => UniqueFileIdType::SECURE,
self::SECURE_RAW => UniqueFileIdType::SECURE,
self::ENCRYPTED => UniqueFileIdType::ENCRYPTED,
self::TEMP => UniqueFileIdType::TEMP,
default => throw new AssertionError("Cannot convert file ID of type ".$this->name." to a unique file ID!")
};
}
}

View File

@ -31,18 +31,16 @@ abstract class PhotoSizeSource
* Source type.
*
*/
private int $type;
private PhotoSizeSourceType $type;
/**
* Set photosize source type.
*
* @param integer $type Type
* @param PhotoSizeSourceType $type Type
*/
public function __construct(int $type)
public function __construct(PhotoSizeSourceType $type)
{
$this->type = $type;
return $this;
}
/**
* Get photosize source type.
@ -51,18 +49,18 @@ abstract class PhotoSizeSource
*
* @psalm-return (
* T is PhotoSizeSourceLegacy ?
* ? \danog\Decoder\PHOTOSIZE_SOURCE_LEGACY
* ? \danog\Decoder\PhotoSizeSourceType::LEGACY
* : (T is PhotoSizeSourceDialogPhoto
* ? \danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_*
* ? \danog\Decoder\PhotoSizeSourceType::DIALOGPHOTO_*
* (T is PhotoSizeSourceStickersetThumbnail
* ? \danog\Decoder\PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL
* : \danog\Decoder\PHOTOSIZE_SOURCE_THUMBNAIL
* ? \danog\Decoder\PhotoSizeSourceType::STICKERSET_THUMBNAIL
* : \danog\Decoder\PhotoSizeSourceType::THUMBNAIL
* )
* )
*
* @internal Internal use
*/
public function getType(): int
public function getType(): PhotoSizeSourceType
{
return $this->type;
}

View File

@ -19,16 +19,16 @@
namespace danog\Decoder\PhotoSizeSource;
use danog\Decoder\PhotoSizeSource;
use const danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL;
use const danog\Decoder\PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY;
use danog\Decoder\PhotoSizeSourceType;
/**
* Represents source of photosize.
*
* @api
*
* @extends PhotoSizeSource<PhotoSizeSourceDialogPhoto>
*/
class PhotoSizeSourceDialogPhoto extends PhotoSizeSource
final class PhotoSizeSourceDialogPhoto extends PhotoSizeSource
{
/**
* ID of dialog.
@ -90,6 +90,6 @@ class PhotoSizeSourceDialogPhoto extends PhotoSizeSource
*/
public function isSmallDialogPhoto(): bool
{
return \in_array($this->getType(), [PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL_LEGACY, PHOTOSIZE_SOURCE_DIALOGPHOTO_SMALL]);
return \in_array($this->getType(), [PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY, PhotoSizeSourceType::DIALOGPHOTO_SMALL], true);
}
}

View File

@ -23,9 +23,11 @@ use danog\Decoder\PhotoSizeSource;
/**
* Represents source of photosize.
*
* @api
*
* @extends PhotoSizeSource<PhotoSizeSourceLegacy>
*/
class PhotoSizeSourceLegacy extends PhotoSizeSource
final class PhotoSizeSourceLegacy extends PhotoSizeSource
{
/**
* Secret legacy ID.

View File

@ -23,9 +23,11 @@ use danog\Decoder\PhotoSizeSource;
/**
* Represents source of photosize.
*
* @api
*
* @extends PhotoSizeSource<PhotoSizeSourceStickersetThumbnail>
*/
class PhotoSizeSourceStickersetThumbnail extends PhotoSizeSource
final class PhotoSizeSourceStickersetThumbnail extends PhotoSizeSource
{
/**
* Stickerset ID.

View File

@ -23,9 +23,11 @@ use danog\Decoder\PhotoSizeSource;
/**
* Represents source of photosize.
*
* @api
*
* @extends PhotoSizeSource<PhotoSizeSourceStickersetThumbnailVersion>
*/
class PhotoSizeSourceStickersetThumbnailVersion extends PhotoSizeSource
final class PhotoSizeSourceStickersetThumbnailVersion extends PhotoSizeSource
{
/**
* Stickerset ID.

View File

@ -18,20 +18,23 @@
namespace danog\Decoder\PhotoSizeSource;
use danog\Decoder\FileIdType;
use danog\Decoder\PhotoSizeSource;
use const danog\Decoder\TYPES;
/**
* Represents source of photosize.
*
* @api
*
* @extends PhotoSizeSource<PhotoSizeSourceThumbnail>
*/
class PhotoSizeSourceThumbnail extends PhotoSizeSource
final class PhotoSizeSourceThumbnail extends PhotoSizeSource
{
/**
* File type of original file.
*
*/
private int $thumbFileType;
private FileIdType $thumbFileType;
/**
* Thumbnail size.
*
@ -42,26 +45,17 @@ class PhotoSizeSourceThumbnail extends PhotoSizeSource
* Get file type of original file.
*
*/
public function getThumbFileType(): int
public function getThumbFileType(): FileIdType
{
return $this->thumbFileType;
}
/**
* Get file type of original file as string.
*
*/
public function getThumbFileTypeString(): string
{
return TYPES[$this->thumbFileType];
}
/**
* Set file type of original file.
*
* @param int $thumbFileType File type of original file
* @param FileIdType $thumbFileType File type of original file
*
*/
public function setThumbFileType(int $thumbFileType): self
public function setThumbFileType(FileIdType $thumbFileType): self
{
$this->thumbFileType = $thumbFileType;

View File

@ -0,0 +1,34 @@
<?php declare(strict_types=1);
/**
* Type enum + helper functions.
*
* This file is part of tg-file-decoder.
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* tg-file-decoder 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 Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://github.com/tg-file-decoder Documentation
*/
namespace danog\Decoder;
enum PhotoSizeSourceType: int
{
case LEGACY = 0;
case THUMBNAIL = 1;
case DIALOGPHOTO_SMALL = 2;
case DIALOGPHOTO_BIG = 3;
case STICKERSET_THUMBNAIL = 4;
case FULL_LEGACY = 5;
case DIALOGPHOTO_SMALL_LEGACY = 6;
case DIALOGPHOTO_BIG_LEGACY = 7;
case STICKERSET_THUMBNAIL_LEGACY = 8;
case STICKERSET_THUMBNAIL_VERSION = 9;
}

View File

@ -24,14 +24,16 @@ use danog\Decoder\PhotoSizeSource\PhotoSizeSourceThumbnail;
/**
* Represents decoded unique bot API file ID.
*
* @api
*/
class UniqueFileId
final class UniqueFileId
{
/**
* File type.
*
*/
private int $type = NONE;
private UniqueFileIdType $type;
/**
* File ID.
*
@ -90,9 +92,9 @@ class UniqueFileId
public function getUniqueBotAPI(): string
{
$fileId = \pack('V', $this->getType());
if ($this->getType() === UNIQUE_WEB) {
if ($this->getType() === UniqueFileIdType::WEB) {
$fileId .= packTLString($this->getUrl());
} elseif ($this->getType() === UNIQUE_PHOTO) {
} elseif ($this->getType() === UniqueFileIdType::PHOTO) {
if ($this->hasVolumeId()) {
$fileId .= packLong($this->getVolumeId());
$fileId .= \pack('l', $this->getLocalId());
@ -122,9 +124,9 @@ class UniqueFileId
$result = new self();
$resultArray = internalDecodeUnique($fileId);
$result->setType($resultArray['typeId']);
if ($result->getType() === UNIQUE_WEB) {
if ($result->getType() === UniqueFileIdType::WEB) {
$result->setUrl($resultArray['url']);
} elseif ($result->getType() === UNIQUE_PHOTO) {
} elseif ($result->getType() === UniqueFileIdType::PHOTO) {
if (isset($resultArray['volume_id'])) {
$result->setVolumeId($resultArray['volume_id']);
$result->setLocalId($resultArray['local_id']);
@ -163,13 +165,13 @@ class UniqueFileId
public static function fromFileId(FileId $fileId): self
{
$result = new self();
$result->setType(FULL_UNIQUE_MAP[$fileId->getType()]);
$result->setType($fileId->getType()->toUnique());
if ($result->hasUrl()) {
$result->setType(UNIQUE_WEB);
$result->setType(UniqueFileIdType::WEB);
}
if ($result->getType() === UNIQUE_WEB) {
if ($result->getType() === UniqueFileIdType::WEB) {
$result->setUrl($fileId->getUrl());
} elseif ($result->getType() === UNIQUE_PHOTO) {
} elseif ($result->getType() === UniqueFileIdType::PHOTO) {
if ($fileId->hasVolumeId()) {
$result->setVolumeId($fileId->getVolumeId());
$result->setLocalId($fileId->getLocalId());
@ -201,20 +203,11 @@ class UniqueFileId
return $result;
}
/**
* Get unique file type as string.
*
*/
public function getTypeName(): string
{
return UNIQUE_TYPES[$this->type];
}
/**
* Get unique file type.
*
*/
public function getType(): int
public function getType(): UniqueFileIdType
{
return $this->type;
}
@ -222,10 +215,10 @@ class UniqueFileId
/**
* Set file type.
*
* @param int $type File type.
* @param UniqueFileIdType $type File type.
*
*/
public function setType(int $type): self
public function setType(UniqueFileIdType $type): self
{
$this->type = $type;

29
src/UniqueFileIdType.php Normal file
View File

@ -0,0 +1,29 @@
<?php declare(strict_types=1);
/**
* Type enum + helper functions.
*
* This file is part of tg-file-decoder.
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* tg-file-decoder 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 Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://github.com/tg-file-decoder Documentation
*/
namespace danog\Decoder;
enum UniqueFileIdType: int
{
case WEB = 0;
case PHOTO = 1;
case DOCUMENT = 2;
case SECURE = 3;
case ENCRYPTED = 4;
case TEMP = 5;
}

View File

@ -1,204 +1,12 @@
<?php declare(strict_types=1);
/**
* Type enum + helper functions.
*
* This file is part of tg-file-decoder.
* tg-file-decoder is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* tg-file-decoder 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 Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with tg-file-decoder.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2019 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
*
* @link https://github.com/tg-file-decoder Documentation
*/
namespace danog\Decoder;
/**
* Thumbnail.
*/
const THUMBNAIL = 0;
/**
* Profile photo.
* Used for users and channels, chat photos are normal PHOTOs.
*/
const PROFILE_PHOTO = 1;
/**
* Normal photos.
*/
const PHOTO = 2;
/**
* Voice messages.
*/
const VOICE = 3;
/**
* Video.
*/
const VIDEO = 4;
/**
* Document.
*/
const DOCUMENT = 5;
/**
* Secret chat document.
*/
const ENCRYPTED = 6;
/**
* Temporary document.
*/
const TEMP = 7;
/**
* Sticker.
*/
const STICKER = 8;
/**
* Music.
*/
const AUDIO = 9;
/**
* GIF.
*/
const ANIMATION = 10;
/**
* Encrypted thumbnail.
*/
const ENCRYPTED_THUMBNAIL = 11;
/**
* Wallpaper.
*/
const WALLPAPER = 12;
/**
* Round video.
*/
const VIDEO_NOTE = 13;
/**
* Passport raw file.
*/
const SECURE_RAW = 14;
/**
* Passport file.
*/
const SECURE = 15;
/**
* Background.
*/
const BACKGROUND = 16;
/**
* Size.
*/
const SIZE = 17;
const NONE = 18;
const TYPES = [
THUMBNAIL => 'thumbnail',
PROFILE_PHOTO => 'profile_photo',
PHOTO => 'photo',
VOICE => 'voice',
VIDEO => 'video',
DOCUMENT => 'document',
ENCRYPTED => 'encrypted',
TEMP => 'temp',
STICKER => 'sticker',
AUDIO => 'audio',
ANIMATION => 'animation',
ENCRYPTED_THUMBNAIL => 'encrypted_thumbnail',
WALLPAPER => 'wallpaper',
VIDEO_NOTE => 'video_note',
SECURE_RAW => 'secure_raw',
SECURE => 'secure',
BACKGROUND => 'background',
SIZE => 'size'
];
const TYPES_IDS = [
'thumbnail' => THUMBNAIL,
'profile_photo' => PROFILE_PHOTO,
'photo' => PHOTO,
'voice' => VOICE,
'video' => VIDEO,
'document' => DOCUMENT,
'encrypted' => ENCRYPTED,
'temp' => TEMP,
'sticker' => STICKER,
'audio' => AUDIO,
'animation' => ANIMATION,
'encrypted_thumbnail' => ENCRYPTED_THUMBNAIL,
'wallpaper' => WALLPAPER,
'video_note' => VIDEO_NOTE,
'secure_raw' => SECURE_RAW,
'secure' => SECURE,
'background' => BACKGROUND,
'size' => SIZE
];
const UNIQUE_WEB = 0;
const UNIQUE_PHOTO = 1;
const UNIQUE_DOCUMENT = 2;
const UNIQUE_SECURE = 3;
const UNIQUE_ENCRYPTED = 4;
const UNIQUE_TEMP = 5;
const UNIQUE_TYPES = [
UNIQUE_WEB => 'web',
UNIQUE_PHOTO => 'photo',
UNIQUE_DOCUMENT => 'document',
UNIQUE_SECURE => 'secure',
UNIQUE_ENCRYPTED => 'encrypted',
UNIQUE_TEMP => 'temp'
];
const UNIQUE_TYPES_IDS = [
'web' => UNIQUE_WEB,
'photo' => UNIQUE_PHOTO,
'document' => UNIQUE_DOCUMENT,
'secure' => UNIQUE_SECURE,
'encrypted' => UNIQUE_ENCRYPTED,
'temp' => UNIQUE_TEMP
];
const FULL_UNIQUE_MAP = [
PHOTO => UNIQUE_PHOTO,
PROFILE_PHOTO => UNIQUE_PHOTO,
THUMBNAIL => UNIQUE_PHOTO,
ENCRYPTED_THUMBNAIL => UNIQUE_PHOTO,
WALLPAPER => UNIQUE_PHOTO,
VIDEO => UNIQUE_DOCUMENT,
VOICE => UNIQUE_DOCUMENT,
DOCUMENT => UNIQUE_DOCUMENT,
STICKER => UNIQUE_DOCUMENT,
AUDIO => UNIQUE_DOCUMENT,
ANIMATION => UNIQUE_DOCUMENT,
VIDEO_NOTE => UNIQUE_DOCUMENT,
BACKGROUND => UNIQUE_DOCUMENT,
SECURE => UNIQUE_SECURE,
SECURE_RAW => UNIQUE_SECURE,
ENCRYPTED => UNIQUE_ENCRYPTED,
TEMP => UNIQUE_TEMP
];
const PHOTOSIZE_SOURCE_LEGACY = 0;
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;
const LONG = PHP_INT_SIZE === 8 ? 'Q' : 'l2';
/** @psalm-suppress UnusedVariable */
$BIG_ENDIAN = \pack('L', 1) === \pack('N', 1);
/**
@ -361,7 +169,6 @@ function rleEncode(string $string): string
}
if ($count > 0) {
$new .= $null.\chr($count);
$count = 0;
}
return $new;
@ -404,15 +211,16 @@ function readTLString(mixed $stream): string
$x = \stream_get_contents($stream, $long_len);
$resto = posmod(-$long_len, 4);
if ($resto > 0) {
\stream_get_contents($stream, $resto);
\fseek($stream, $resto, SEEK_CUR);
}
} else {
$x = $l ? \stream_get_contents($stream, $l) : '';
$resto = posmod(-($l + 1), 4);
if ($resto > 0) {
\stream_get_contents($stream, $resto);
\fseek($stream, $resto, SEEK_CUR);
}
}
\assert($x !== false);
return $x;
}
@ -462,10 +270,7 @@ function internalDecode(string $fileId): array
$result['hasWebLocation'] = (bool) ($result['typeId'] & WEB_LOCATION_FLAG);
$result['typeId'] &= ~FILE_REFERENCE_FLAG;
$result['typeId'] &= ~WEB_LOCATION_FLAG;
if (!isset(TYPES[$result['typeId']])) {
throw new \InvalidArgumentException("Invalid file type provided: {$result['typeId']}");
}
$result['type'] = TYPES[$result['typeId']];
$result['type'] = FileIdType::from($result['typeId']);
$res = \fopen('php://memory', 'rw+b');
\fwrite($res, \substr($fileId, 8));
\fseek($res, 0);
@ -485,38 +290,38 @@ function internalDecode(string $fileId): array
fixLong($result, 'id');
fixLong($result, 'access_hash');
if ($result['typeId'] <= PHOTO) {
if ($result['typeId'] <= FileIdType::PHOTO->value) {
$parsePhotoSize = function () use (&$result, &$fileId) {
$result['photosize_source'] = $result['subVersion'] >= 4 ? \unpack('V', \stream_get_contents($fileId, 4))[1] : 0;
switch ($result['photosize_source']) {
case PHOTOSIZE_SOURCE_LEGACY:
case PhotoSizeSourceType::LEGACY:
$result += \unpack(LONG.'secret', \stream_get_contents($fileId, 8));
fixLong($result, 'secret');
break;
case PHOTOSIZE_SOURCE_THUMBNAIL:
case PhotoSizeSourceType::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';
case PhotoSizeSourceType::DIALOGPHOTO_BIG:
case PhotoSizeSourceType::DIALOGPHOTO_SMALL:
$result['photo_size'] = $result['photosize_source'] === PhotoSizeSourceType::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:
case PhotoSizeSourceType::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:
case PhotoSizeSourceType::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';
case PhotoSizeSourceType::DIALOGPHOTO_BIG_LEGACY:
case PhotoSizeSourceType::DIALOGPHOTO_SMALL_LEGACY:
$result['photo_size'] = $result['photosize_source'] === PhotoSizeSourceType::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');
@ -524,7 +329,7 @@ function internalDecode(string $fileId): array
$result += \unpack(LONG.'volume_id/llocal_id', \stream_get_contents($fileId, 12));
fixLong($result, 'volume_id');
break;
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_LEGACY:
case PhotoSizeSourceType::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');
@ -533,7 +338,7 @@ function internalDecode(string $fileId): array
fixLong($result, 'volume_id');
break;
case PHOTOSIZE_SOURCE_STICKERSET_THUMBNAIL_VERSION:
case PhotoSizeSourceType::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');
@ -579,13 +384,10 @@ function internalDecodeUnique(string $fileId): array
$fileId = rleDecode(base64urlDecode($fileId));
$result = \unpack('VtypeId', $fileId);
if (!isset(UNIQUE_TYPES[$result['typeId']])) {
throw new \InvalidArgumentException("Invalid file type provided: {$result['typeId']}");
}
$result['type'] = UNIQUE_TYPES[$result['typeId']];
$result['type'] = UniqueFileIdType::from($result['typeId']);
$fileId = \substr($fileId, 4);
if ($result['typeId'] === UNIQUE_WEB) {
if ($result['typeId'] === UniqueFileIdType::WEB) {
$res = \fopen('php://memory', 'rw+b');
\fwrite($res, $fileId);
\fseek($res, 0);
@ -624,5 +426,6 @@ function internalDecodeUnique(string $fileId): array
\trigger_error("Unique file ID $orig has $l bytes of leftover data");
}
\assert($result !== false);
return $result;
}