Security update to Drupal 8.4.6
[yaffs-website] / vendor / guzzlehttp / psr7 / src / AppendStream.php
1 <?php
2 namespace GuzzleHttp\Psr7;
3
4 use Psr\Http\Message\StreamInterface;
5
6 /**
7  * Reads from multiple streams, one after the other.
8  *
9  * This is a read-only stream decorator.
10  */
11 class AppendStream implements StreamInterface
12 {
13     /** @var StreamInterface[] Streams being decorated */
14     private $streams = [];
15
16     private $seekable = true;
17     private $current = 0;
18     private $pos = 0;
19     private $detached = false;
20
21     /**
22      * @param StreamInterface[] $streams Streams to decorate. Each stream must
23      *                                   be readable.
24      */
25     public function __construct(array $streams = [])
26     {
27         foreach ($streams as $stream) {
28             $this->addStream($stream);
29         }
30     }
31
32     public function __toString()
33     {
34         try {
35             $this->rewind();
36             return $this->getContents();
37         } catch (\Exception $e) {
38             return '';
39         }
40     }
41
42     /**
43      * Add a stream to the AppendStream
44      *
45      * @param StreamInterface $stream Stream to append. Must be readable.
46      *
47      * @throws \InvalidArgumentException if the stream is not readable
48      */
49     public function addStream(StreamInterface $stream)
50     {
51         if (!$stream->isReadable()) {
52             throw new \InvalidArgumentException('Each stream must be readable');
53         }
54
55         // The stream is only seekable if all streams are seekable
56         if (!$stream->isSeekable()) {
57             $this->seekable = false;
58         }
59
60         $this->streams[] = $stream;
61     }
62
63     public function getContents()
64     {
65         return copy_to_string($this);
66     }
67
68     /**
69      * Closes each attached stream.
70      *
71      * {@inheritdoc}
72      */
73     public function close()
74     {
75         $this->pos = $this->current = 0;
76
77         foreach ($this->streams as $stream) {
78             $stream->close();
79         }
80
81         $this->streams = [];
82     }
83
84     /**
85      * Detaches each attached stream
86      *
87      * {@inheritdoc}
88      */
89     public function detach()
90     {
91         $this->close();
92         $this->detached = true;
93     }
94
95     public function tell()
96     {
97         return $this->pos;
98     }
99
100     /**
101      * Tries to calculate the size by adding the size of each stream.
102      *
103      * If any of the streams do not return a valid number, then the size of the
104      * append stream cannot be determined and null is returned.
105      *
106      * {@inheritdoc}
107      */
108     public function getSize()
109     {
110         $size = 0;
111
112         foreach ($this->streams as $stream) {
113             $s = $stream->getSize();
114             if ($s === null) {
115                 return null;
116             }
117             $size += $s;
118         }
119
120         return $size;
121     }
122
123     public function eof()
124     {
125         return !$this->streams ||
126             ($this->current >= count($this->streams) - 1 &&
127              $this->streams[$this->current]->eof());
128     }
129
130     public function rewind()
131     {
132         $this->seek(0);
133     }
134
135     /**
136      * Attempts to seek to the given position. Only supports SEEK_SET.
137      *
138      * {@inheritdoc}
139      */
140     public function seek($offset, $whence = SEEK_SET)
141     {
142         if (!$this->seekable) {
143             throw new \RuntimeException('This AppendStream is not seekable');
144         } elseif ($whence !== SEEK_SET) {
145             throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
146         }
147
148         $this->pos = $this->current = 0;
149
150         // Rewind each stream
151         foreach ($this->streams as $i => $stream) {
152             try {
153                 $stream->rewind();
154             } catch (\Exception $e) {
155                 throw new \RuntimeException('Unable to seek stream '
156                     . $i . ' of the AppendStream', 0, $e);
157             }
158         }
159
160         // Seek to the actual position by reading from each stream
161         while ($this->pos < $offset && !$this->eof()) {
162             $result = $this->read(min(8096, $offset - $this->pos));
163             if ($result === '') {
164                 break;
165             }
166         }
167     }
168
169     /**
170      * Reads from all of the appended streams until the length is met or EOF.
171      *
172      * {@inheritdoc}
173      */
174     public function read($length)
175     {
176         $buffer = '';
177         $total = count($this->streams) - 1;
178         $remaining = $length;
179         $progressToNext = false;
180
181         while ($remaining > 0) {
182
183             // Progress to the next stream if needed.
184             if ($progressToNext || $this->streams[$this->current]->eof()) {
185                 $progressToNext = false;
186                 if ($this->current === $total) {
187                     break;
188                 }
189                 $this->current++;
190             }
191
192             $result = $this->streams[$this->current]->read($remaining);
193
194             // Using a loose comparison here to match on '', false, and null
195             if ($result == null) {
196                 $progressToNext = true;
197                 continue;
198             }
199
200             $buffer .= $result;
201             $remaining = $length - strlen($buffer);
202         }
203
204         $this->pos += strlen($buffer);
205
206         return $buffer;
207     }
208
209     public function isReadable()
210     {
211         return true;
212     }
213
214     public function isWritable()
215     {
216         return false;
217     }
218
219     public function isSeekable()
220     {
221         return $this->seekable;
222     }
223
224     public function write($string)
225     {
226         throw new \RuntimeException('Cannot write to an AppendStream');
227     }
228
229     public function getMetadata($key = null)
230     {
231         return $key ? null : [];
232     }
233 }