Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\VarDumper\Caster;
13
 
14
use FFI\CData;
15
use FFI\CType;
16
use Symfony\Component\VarDumper\Cloner\Stub;
17
 
18
/**
19
 * Casts FFI extension classes to array representation.
20
 *
21
 * @author Nesmeyanov Kirill <nesk@xakep.ru>
22
 */
23
final class FFICaster
24
{
25
    /**
26
     * In case of "char*" contains a string, the length of which depends on
27
     * some other parameter, then during the generation of the string it is
28
     * possible to go beyond the allowable memory area.
29
     *
30
     * This restriction serves to ensure that processing does not take
31
     * up the entire allowable PHP memory limit.
32
     */
33
    private const MAX_STRING_LENGTH = 255;
34
 
35
    public static function castCTypeOrCData(CData|CType $data, array $args, Stub $stub): array
36
    {
37
        if ($data instanceof CType) {
38
            $type = $data;
39
            $data = null;
40
        } else {
41
            $type = \FFI::typeof($data);
42
        }
43
 
44
        $stub->class = sprintf('%s<%s> size %d align %d', ($data ?? $type)::class, $type->getName(), $type->getSize(), $type->getAlignment());
45
 
46
        return match ($type->getKind()) {
47
            CType::TYPE_FLOAT,
48
            CType::TYPE_DOUBLE,
49
            \defined('\FFI\CType::TYPE_LONGDOUBLE') ? CType::TYPE_LONGDOUBLE : -1,
50
            CType::TYPE_UINT8,
51
            CType::TYPE_SINT8,
52
            CType::TYPE_UINT16,
53
            CType::TYPE_SINT16,
54
            CType::TYPE_UINT32,
55
            CType::TYPE_SINT32,
56
            CType::TYPE_UINT64,
57
            CType::TYPE_SINT64,
58
            CType::TYPE_BOOL,
59
            CType::TYPE_CHAR,
60
            CType::TYPE_ENUM => null !== $data ? [Caster::PREFIX_VIRTUAL.'cdata' => $data->cdata] : [],
61
            CType::TYPE_POINTER => self::castFFIPointer($stub, $type, $data),
62
            CType::TYPE_STRUCT => self::castFFIStructLike($type, $data),
63
            CType::TYPE_FUNC => self::castFFIFunction($stub, $type),
64
            default => $args,
65
        };
66
    }
67
 
68
    private static function castFFIFunction(Stub $stub, CType $type): array
69
    {
70
        $arguments = [];
71
 
72
        for ($i = 0, $count = $type->getFuncParameterCount(); $i < $count; ++$i) {
73
            $param = $type->getFuncParameterType($i);
74
 
75
            $arguments[] = $param->getName();
76
        }
77
 
78
        $abi = match ($type->getFuncABI()) {
79
            CType::ABI_DEFAULT,
80
            CType::ABI_CDECL => '[cdecl]',
81
            CType::ABI_FASTCALL => '[fastcall]',
82
            CType::ABI_THISCALL => '[thiscall]',
83
            CType::ABI_STDCALL => '[stdcall]',
84
            CType::ABI_PASCAL => '[pascal]',
85
            CType::ABI_REGISTER => '[register]',
86
            CType::ABI_MS => '[ms]',
87
            CType::ABI_SYSV => '[sysv]',
88
            CType::ABI_VECTORCALL => '[vectorcall]',
89
            default => '[unknown abi]'
90
        };
91
 
92
        $returnType = $type->getFuncReturnType();
93
 
94
        $stub->class = $abi.' callable('.implode(', ', $arguments).'): '
95
            .$returnType->getName();
96
 
97
        return [Caster::PREFIX_VIRTUAL.'returnType' => $returnType];
98
    }
99
 
100
    private static function castFFIPointer(Stub $stub, CType $type, CData $data = null): array
101
    {
102
        $ptr = $type->getPointerType();
103
 
104
        if (null === $data) {
105
            return [Caster::PREFIX_VIRTUAL.'0' => $ptr];
106
        }
107
 
108
        return match ($ptr->getKind()) {
109
            CType::TYPE_CHAR => [Caster::PREFIX_VIRTUAL.'cdata' => self::castFFIStringValue($data)],
110
            CType::TYPE_FUNC => self::castFFIFunction($stub, $ptr),
111
            default => [Caster::PREFIX_VIRTUAL.'cdata' => $data[0]],
112
        };
113
    }
114
 
115
    private static function castFFIStringValue(CData $data): string|CutStub
116
    {
117
        $result = [];
118
 
119
        for ($i = 0; $i < self::MAX_STRING_LENGTH; ++$i) {
120
            $result[$i] = $data[$i];
121
 
122
            if ("\0" === $result[$i]) {
123
                return implode('', $result);
124
            }
125
        }
126
 
127
        $string = implode('', $result);
128
        $stub = new CutStub($string);
129
        $stub->cut = -1;
130
        $stub->value = $string;
131
 
132
        return $stub;
133
    }
134
 
135
    private static function castFFIStructLike(CType $type, CData $data = null): array
136
    {
137
        $isUnion = ($type->getAttributes() & CType::ATTR_UNION) === CType::ATTR_UNION;
138
 
139
        $result = [];
140
 
141
        foreach ($type->getStructFieldNames() as $name) {
142
            $field = $type->getStructFieldType($name);
143
 
144
            // Retrieving the value of a field from a union containing
145
            // a pointer is not a safe operation, because may contain
146
            // incorrect data.
147
            $isUnsafe = $isUnion && CType::TYPE_POINTER === $field->getKind();
148
 
149
            if ($isUnsafe) {
150
                $result[Caster::PREFIX_VIRTUAL.$name.'?'] = $field;
151
            } elseif (null === $data) {
152
                $result[Caster::PREFIX_VIRTUAL.$name] = $field;
153
            } else {
154
                $fieldName = $data->{$name} instanceof CData ? '' : $field->getName().' ';
155
                $result[Caster::PREFIX_VIRTUAL.$fieldName.$name] = $data->{$name};
156
            }
157
        }
158
 
159
        return $result;
160
    }
161
}