DirectoryString::fromASN1()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\X501\ASN1\AttributeValue\Feature;
6
7
use Sop\ASN1\Element;
8
use Sop\ASN1\Type\Primitive\BMPString;
9
use Sop\ASN1\Type\Primitive\PrintableString;
10
use Sop\ASN1\Type\Primitive\T61String;
11
use Sop\ASN1\Type\Primitive\UniversalString;
12
use Sop\ASN1\Type\Primitive\UTF8String;
13
use Sop\ASN1\Type\UnspecifiedType;
14
use Sop\X501\ASN1\AttributeValue\AttributeValue;
15
use Sop\X501\DN\DNParser;
16
use Sop\X501\MatchingRule\CaseIgnoreMatch;
17
use Sop\X501\MatchingRule\MatchingRule;
18
use Sop\X501\StringPrep\TranscodeStep;
19
20
/**
21
 * Base class for attribute values having *(Unbounded)DirectoryString* as a syntax.
22
 *
23
 * @see https://www.itu.int/ITU-T/formal-language/itu-t/x/x520/2012/SelectedAttributeTypes.html#SelectedAttributeTypes.UnboundedDirectoryString
24
 */
25
abstract class DirectoryString extends AttributeValue
26
{
27
    /**
28
     * Teletex string syntax.
29
     *
30
     * @var int
31
     */
32
    const TELETEX = Element::TYPE_T61_STRING;
33
34
    /**
35
     * Printable string syntax.
36
     *
37
     * @var int
38
     */
39
    const PRINTABLE = Element::TYPE_PRINTABLE_STRING;
40
41
    /**
42
     * BMP string syntax.
43
     *
44
     * @var int
45
     */
46
    const BMP = Element::TYPE_BMP_STRING;
47
48
    /**
49
     * Universal string syntax.
50
     *
51
     * @var int
52
     */
53
    const UNIVERSAL = Element::TYPE_UNIVERSAL_STRING;
54
55
    /**
56
     * UTF-8 string syntax.
57
     *
58
     * @var int
59
     */
60
    const UTF8 = Element::TYPE_UTF8_STRING;
61
62
    /**
63
     * Mapping from syntax enumeration to ASN.1 class name.
64
     *
65
     * @internal
66
     *
67
     * @var array
68
     */
69
    const MAP_TAG_TO_CLASS = [
70
        self::TELETEX => T61String::class,
71
        self::PRINTABLE => PrintableString::class,
72
        self::UNIVERSAL => UniversalString::class,
73
        self::UTF8 => UTF8String::class,
74
        self::BMP => BMPString::class,
75
    ];
76
77
    /**
78
     * ASN.1 type tag for the chosen syntax.
79
     *
80
     * @var int
81
     */
82
    protected $_stringTag;
83
84
    /**
85
     * String value.
86
     *
87
     * @var string
88
     */
89
    protected $_string;
90
91
    /**
92
     * Constructor.
93
     *
94
     * @param string $value      String value
95
     * @param int    $string_tag Syntax choice
96
     */
97 74
    public function __construct(string $value, int $string_tag)
98
    {
99 74
        $this->_string = $value;
100 74
        $this->_stringTag = $string_tag;
101 74
    }
102
103
    /**
104
     * {@inheritdoc}
105
     *
106
     * @return self
107
     */
108 51
    public static function fromASN1(UnspecifiedType $el): AttributeValue
109
    {
110 51
        $tag = $el->tag();
111
        // validate tag
112 51
        self::_tagToASN1Class($tag);
113 50
        return new static($el->asString()->string(), $tag);
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119 22
    public function toASN1(): Element
120
    {
121 22
        $cls = self::_tagToASN1Class($this->_stringTag);
122 21
        return new $cls($this->_string);
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 25
    public function stringValue(): string
129
    {
130 25
        return $this->_string;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 17
    public function equalityMatchingRule(): MatchingRule
137
    {
138 17
        return new CaseIgnoreMatch($this->_stringTag);
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 17
    public function rfc2253String(): string
145
    {
146
        // TeletexString is encoded as binary
147 17
        if (self::TELETEX === $this->_stringTag) {
148 1
            return $this->_transcodedString();
149
        }
150 16
        return DNParser::escapeString($this->_transcodedString());
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156 17
    protected function _transcodedString(): string
157
    {
158 17
        $step = new TranscodeStep($this->_stringTag);
159 17
        return $step->apply($this->_string);
160
    }
161
162
    /**
163
     * Get ASN.1 class name for given DirectoryString type tag.
164
     *
165
     * @param int $tag
166
     *
167
     * @throws \UnexpectedValueException
168
     *
169
     * @return string
170
     */
171 70
    private static function _tagToASN1Class(int $tag): string
172
    {
173 70
        if (!array_key_exists($tag, self::MAP_TAG_TO_CLASS)) {
174 2
            throw new \UnexpectedValueException(
175 2
                sprintf('Type %s is not valid DirectoryString.',
176 2
                    Element::tagToName($tag)));
177
        }
178 68
        return self::MAP_TAG_TO_CLASS[$tag];
179
    }
180
}
181