Completed
Push — id3-metadata-objects ( e55453...161f4c )
by Daniel
11:12
created

ExtendedHeaderReader::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
/**
3
 * This file is part of the Metadata package.
4
 *
5
 * @author Daniel Schröder <[email protected]>
6
 */
7
8
namespace GravityMedia\Metadata\ID3v2\Reader;
9
10
use GravityMedia\Metadata\ID3v2\Enum\ExtendedHeaderFlag;
11
use GravityMedia\Metadata\ID3v2\Enum\Version;
12
use GravityMedia\Metadata\ID3v2\ExtendedHeader;
13
use GravityMedia\Metadata\ID3v2\Stream\SynchsafeInteger32Reader;
14
use GravityMedia\Metadata\Metadata\ExtendedHeaderInterface;
15
use GravityMedia\Metadata\Metadata\HeaderInterface;
16
use GravityMedia\Stream\Enum\ByteOrder;
17
use GravityMedia\Stream\Reader\Integer16Reader;
18
use GravityMedia\Stream\Reader\Integer32Reader;
19
use GravityMedia\Stream\Reader\Integer8Reader;
20
use GravityMedia\Stream\StreamInterface;
21
22
/**
23
 * ID3v2 extended header reader
24
 *
25
 * @package GravityMedia\Metadata\ID3v2\Reader
26
 */
27
class ExtendedHeaderReader
28
{
29
    /**
30
     * @var StreamInterface
31
     */
32
    protected $stream;
33
34
    /**
35
     * @var HeaderInterface
36
     */
37
    protected $header;
38
39
    /**
40
     * @var Integer8Reader
41
     */
42
    protected $integer8Reader;
43
44
    /**
45
     * @var Integer16Reader
46
     */
47
    protected $integer16Reader;
48
49
    /**
50
     * @var Integer32Reader
51
     */
52
    protected $integer32Reader;
53
54
    /**
55
     * @var SynchsafeInteger32Reader
56
     */
57
    protected $synchsafeInteger32Reader;
58
59
    /**
60
     * Create ID3v2 extended header reader.
61
     *
62
     * @param StreamInterface $stream
63
     * @param HeaderInterface $header
64
     */
65
    public function __construct(StreamInterface $stream, HeaderInterface $header)
66
    {
67
        $this->stream = $stream;
68
        $this->header = $header;
69
    }
70
71
    /**
72
     * Get 8-bit integer reader.
73
     *
74
     * @return Integer8Reader
75
     */
76 View Code Duplication
    public function getInteger8Reader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
77
    {
78
        if (null === $this->integer8Reader) {
79
            $this->integer8Reader = new Integer8Reader($this->stream);
80
        }
81
82
        return $this->integer8Reader;
83
    }
84
85
    /**
86
     * Get 16-bit integer reader
87
     *
88
     * @return Integer16Reader
89
     */
90 View Code Duplication
    public function getInteger16Reader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
91
    {
92
        if (null === $this->integer16Reader) {
93
            $this->integer16Reader = new Integer16Reader($this->stream);
94
            $this->integer16Reader->setByteOrder(ByteOrder::BIG_ENDIAN);
95
        }
96
97
        return $this->integer16Reader;
98
    }
99
100
    /**
101
     * Get 32-bit integer reader
102
     *
103
     * @return Integer32Reader
104
     */
105 View Code Duplication
    public function getInteger32Reader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
    {
107
        if (null === $this->integer32Reader) {
108
            $this->integer32Reader = new Integer32Reader($this->stream);
109
            $this->integer32Reader->setByteOrder(ByteOrder::BIG_ENDIAN);
110
        }
111
112
        return $this->integer32Reader;
113
    }
114
115
    /**
116
     * Get synchsafe 32-bit integer reader
117
     *
118
     * @return SynchsafeInteger32Reader
119
     */
120 View Code Duplication
    public function getSynchsafeInteger32Reader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
    {
122
        if (null === $this->synchsafeInteger32Reader) {
123
            $this->synchsafeInteger32Reader = new SynchsafeInteger32Reader($this->stream);
124
            $this->synchsafeInteger32Reader->setByteOrder(ByteOrder::BIG_ENDIAN);
125
        }
126
127
        return $this->synchsafeInteger32Reader;
128
    }
129
130
    /**
131
     * Read ID3v2 extended header size.
132
     *
133
     * @return int
134
     */
135
    protected function readSize()
136
    {
137
        if (Version::VERSION_23 === $this->header->getVersion()) {
138
            return $this->getInteger32Reader()->read();
139
        }
140
141
        return $this->getSynchsafeInteger32Reader()->read();
142
    }
143
144
    /**
145
     * Read ID3v2 extended header flags.
146
     *
147
     * @return array
148
     */
149
    protected function readFlags()
150
    {
151
        if (Version::VERSION_23 === $this->header->getVersion()) {
152
            $flags = $this->getInteger16Reader()->read();
153
154
            return [
155
                ExtendedHeaderFlag::FLAG_CRC_DATA_PRESENT => (bool)($flags & 0x8000)
156
            ];
157
        }
158
159
        $this->stream->seek(1, SEEK_CUR);
160
161
        $flags = $this->getInteger8Reader()->read();
162
163
        return [
164
            ExtendedHeaderFlag::FLAG_TAG_IS_AN_UPDATE => (bool)($flags & 0x40),
165
            ExtendedHeaderFlag::FLAG_CRC_DATA_PRESENT => (bool)($flags & 0x20),
166
            ExtendedHeaderFlag::FLAG_TAG_RESTRICTIONS => (bool)($flags & 0x10)
167
        ];
168
    }
169
170
    /**
171
     * Read ID3v2 extended header padding.
172
     *
173
     * @return int
174
     */
175
    protected function readPadding()
176
    {
177
        return $this->getInteger32Reader()->read();
178
    }
179
180
    /**
181
     * Read ID3v2 extended header CRC-32 data.
182
     *
183
     * @return int
184
     */
185
    protected function readCrc32()
186
    {
187
        if (Version::VERSION_23 === $this->header->getVersion()) {
188
            return $this->getInteger32Reader()->read();
189
        }
190
191
        $this->stream->seek(1, SEEK_CUR);
192
193
        return $this->getInteger8Reader()->read() * (0xfffffff + 1) + $this->getSynchsafeInteger32Reader()->read();
194
    }
195
196
    /**
197
     * Read ID3v2 extended header restrictions.
198
     *
199
     * @return int
200
     */
201
    protected function readRestrictions()
202
    {
203
        $this->stream->seek(1, SEEK_CUR);
204
205
        return $this->getInteger8Reader()->read();
206
    }
207
208
    /**
209
     * Read ID3v2 extended header.
210
     *
211
     * @return ExtendedHeaderInterface
212
     */
213
    public function read()
214
    {
215
        $extendedHeader = new ExtendedHeader();
216
        $extendedHeader
217
            ->setSize($this->readSize())
218
            ->setFlags($this->readFlags());
219
220
        // Only in ID3v2.3
221
        if (Version::VERSION_23 === $this->header->getVersion()) {
222
            $extendedHeader->setPadding($this->readPadding());
223
        }
224
225
        // Only in ID3v2.3
226
        if ($extendedHeader->isFlagEnabled(ExtendedHeaderFlag::FLAG_TAG_IS_AN_UPDATE)) {
227
            $this->stream->seek(1, SEEK_CUR);
228
        }
229
230
        if ($extendedHeader->isFlagEnabled(ExtendedHeaderFlag::FLAG_CRC_DATA_PRESENT)) {
231
            $extendedHeader->setCrc32($this->readCrc32());
232
        }
233
234
        // Only in ID3v2.4
235
        if ($extendedHeader->isFlagEnabled(ExtendedHeaderFlag::FLAG_TAG_RESTRICTIONS)) {
236
            $extendedHeader->setRestrictions($this->readRestrictions());
237
        }
238
239
        return $extendedHeader;
240
    }
241
}
242