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

TagReader::read()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 41
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 41
rs 8.439
cc 6
eloc 22
nc 13
nop 0
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\Encoder\Unsynchronisation;
11
use GravityMedia\Metadata\ID3v2\Enum\HeaderFlag;
12
use GravityMedia\Metadata\ID3v2\Tag;
13
use GravityMedia\Metadata\Metadata\HeaderInterface;
14
use GravityMedia\Metadata\Metadata\MetadataInterface;
15
use GravityMedia\Metadata\Metadata\TagInterface;
16
use GravityMedia\Stream\Stream;
17
use GravityMedia\Stream\StreamInterface;
18
19
/**
20
 * ID3v2 tag reader.
21
 *
22
 * @package GravityMedia\Metadata\ID3v2\Reader
23
 */
24
class TagReader
25
{
26
    /**
27
     * @var MetadataInterface
28
     */
29
    protected $metadata;
30
31
    /**
32
     * @var StreamInterface
33
     */
34
    protected $stream;
35
36
    /**
37
     * @var HeaderReader
38
     */
39
    protected $headerReader;
40
41
    /**
42
     * Create ID3v2 tag reader.
43
     *
44
     * @param MetadataInterface $metadata
45
     * @param StreamInterface $stream
46
     */
47
    public function __construct(MetadataInterface $metadata, StreamInterface $stream)
48
    {
49
        $this->metadata = $metadata;
50
        $this->stream = $stream;
51
    }
52
53
    /**
54
     * Get header reader.
55
     *
56
     * @return HeaderReader
57
     */
58
    public function getHeaderReader()
59
    {
60
        if (null === $this->headerReader) {
61
            $this->headerReader = new HeaderReader($this->stream);
62
        }
63
64
        return $this->headerReader;
65
    }
66
67
    /**
68
     * Read data.
69
     *
70
     * @param HeaderInterface $header
71
     *
72
     * @return string
73
     */
74
    protected function readData(HeaderInterface $header)
75
    {
76
        $this->stream->seek(10);
77
        $data = $this->stream->read($header->getSize());
78
79
        if ($header->isFlagEnabled(HeaderFlag::FLAG_COMPRESSION)) {
80
            $data = gzuncompress($data);
81
        }
82
83
        if ($header->isFlagEnabled(HeaderFlag::FLAG_UNSYNCHRONISATION)) {
84
            $data = Unsynchronisation::decode($data);
85
        }
86
87
        return $data;
88
    }
89
90
    /**
91
     * Create data stream.
92
     *
93
     * @param string $data
94
     *
95
     * @return StreamInterface
96
     */
97
    protected function createDataStream($data)
98
    {
99
        $resource = fopen('php://temp', 'r+b');
100
        $stream = Stream::fromResource($resource);
101
        $stream->write($data);
102
        $stream->rewind();
103
104
        return $stream;
105
    }
106
107
    /**
108
     * Read ID3v2 tag.
109
     *
110
     * @return null|TagInterface
111
     */
112
    public function read()
113
    {
114
        if (!$this->metadata->exists()) {
115
            return null;
116
        }
117
118
        $header = $this->getHeaderReader()->read();
119
        $stream = $this->createDataStream($this->readData($header));
120
121
        $tag = new Tag($header);
122
        $size = $stream->getSize();
123
124
        if ($header->isFlagEnabled(HeaderFlag::FLAG_EXTENDED_HEADER)) {
125
            $extendedHeaderReader = new ExtendedHeaderReader($stream, $header);
126
            $extendedHeader = $extendedHeaderReader->read();
127
128
            $tag->setExtendedHeader($extendedHeader);
129
130
            $size -= $extendedHeader->getSize();
131
        }
132
133
        if ($header->isFlagEnabled(HeaderFlag::FLAG_EXTENDED_HEADER)) {
134
            // TODO: Read footer from stream
135
136
            $size -= 10;
137
        }
138
139
        $frameReader = new FrameReader($stream, $header);
140
        while ($size > 0) {
141
            $frame = $frameReader->read();
142
            if (0 === $frame->getSize()) {
143
                break;
144
            }
145
146
            $tag->addFrame($frame);
147
148
            $size -= $frame->getSize();
149
        }
150
151
        return $tag;
152
    }
153
}
154