Security update for Core, with self-updated composer
[yaffs-website] / vendor / zendframework / zend-stdlib / src / StringWrapper / AbstractStringWrapper.php
1 <?php
2 /**
3  * Zend Framework (http://framework.zend.com/)
4  *
5  * @link      http://github.com/zendframework/zf2 for the canonical source repository
6  * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7  * @license   http://framework.zend.com/license/new-bsd New BSD License
8  */
9
10 namespace Zend\Stdlib\StringWrapper;
11
12 use Zend\Stdlib\Exception;
13 use Zend\Stdlib\StringUtils;
14
15 abstract class AbstractStringWrapper implements StringWrapperInterface
16 {
17     /**
18      * The character encoding working on
19      * @var string|null
20      */
21     protected $encoding = 'UTF-8';
22
23     /**
24      * An optionally character encoding to convert to
25      * @var string|null
26      */
27     protected $convertEncoding;
28
29     /**
30      * Check if the given character encoding is supported by this wrapper
31      * and the character encoding to convert to is also supported.
32      *
33      * @param  string      $encoding
34      * @param  string|null $convertEncoding
35      * @return bool
36      */
37     public static function isSupported($encoding, $convertEncoding = null)
38     {
39         $supportedEncodings = static::getSupportedEncodings();
40
41         if (! in_array(strtoupper($encoding), $supportedEncodings)) {
42             return false;
43         }
44
45         if ($convertEncoding !== null && ! in_array(strtoupper($convertEncoding), $supportedEncodings)) {
46             return false;
47         }
48
49         return true;
50     }
51
52     /**
53      * Set character encoding working with and convert to
54      *
55      * @param string      $encoding         The character encoding to work with
56      * @param string|null $convertEncoding  The character encoding to convert to
57      * @return StringWrapperInterface
58      */
59     public function setEncoding($encoding, $convertEncoding = null)
60     {
61         $supportedEncodings = static::getSupportedEncodings();
62
63         $encodingUpper = strtoupper($encoding);
64         if (! in_array($encodingUpper, $supportedEncodings)) {
65             throw new Exception\InvalidArgumentException(
66                 'Wrapper doesn\'t support character encoding "' . $encoding . '"'
67             );
68         }
69
70         if ($convertEncoding !== null) {
71             $convertEncodingUpper = strtoupper($convertEncoding);
72             if (! in_array($convertEncodingUpper, $supportedEncodings)) {
73                 throw new Exception\InvalidArgumentException(
74                     'Wrapper doesn\'t support character encoding "' . $convertEncoding . '"'
75                 );
76             }
77
78             $this->convertEncoding = $convertEncodingUpper;
79         } else {
80             $this->convertEncoding = null;
81         }
82         $this->encoding = $encodingUpper;
83
84         return $this;
85     }
86
87     /**
88      * Get the defined character encoding to work with
89      *
90      * @return string
91      * @throws Exception\LogicException If no encoding was defined
92      */
93     public function getEncoding()
94     {
95         return $this->encoding;
96     }
97
98     /**
99      * Get the defined character encoding to convert to
100      *
101      * @return string|null
102     */
103     public function getConvertEncoding()
104     {
105         return $this->convertEncoding;
106     }
107
108     /**
109      * Convert a string from defined character encoding to the defined convert encoding
110      *
111      * @param string  $str
112      * @param bool $reverse
113      * @return string|false
114      */
115     public function convert($str, $reverse = false)
116     {
117         $encoding        = $this->getEncoding();
118         $convertEncoding = $this->getConvertEncoding();
119         if ($convertEncoding === null) {
120             throw new Exception\LogicException(
121                 'No convert encoding defined'
122             );
123         }
124
125         if ($encoding === $convertEncoding) {
126             return $str;
127         }
128
129         $from = $reverse ? $convertEncoding : $encoding;
130         $to   = $reverse ? $encoding : $convertEncoding;
131         throw new Exception\RuntimeException(sprintf(
132             'Converting from "%s" to "%s" isn\'t supported by this string wrapper',
133             $from,
134             $to
135         ));
136     }
137
138     /**
139      * Wraps a string to a given number of characters
140      *
141      * @param  string  $string
142      * @param  int $width
143      * @param  string  $break
144      * @param  bool $cut
145      * @return string|false
146      */
147     public function wordWrap($string, $width = 75, $break = "\n", $cut = false)
148     {
149         $string = (string) $string;
150         if ($string === '') {
151             return '';
152         }
153
154         $break = (string) $break;
155         if ($break === '') {
156             throw new Exception\InvalidArgumentException('Break string cannot be empty');
157         }
158
159         $width = (int) $width;
160         if ($width === 0 && $cut) {
161             throw new Exception\InvalidArgumentException('Cannot force cut when width is zero');
162         }
163
164         if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
165             return wordwrap($string, $width, $break, $cut);
166         }
167
168         $stringWidth = $this->strlen($string);
169         $breakWidth  = $this->strlen($break);
170
171         $result    = '';
172         $lastStart = $lastSpace = 0;
173
174         for ($current = 0; $current < $stringWidth; $current++) {
175             $char = $this->substr($string, $current, 1);
176
177             $possibleBreak = $char;
178             if ($breakWidth !== 1) {
179                 $possibleBreak = $this->substr($string, $current, $breakWidth);
180             }
181
182             if ($possibleBreak === $break) {
183                 $result    .= $this->substr($string, $lastStart, $current - $lastStart + $breakWidth);
184                 $current   += $breakWidth - 1;
185                 $lastStart  = $lastSpace = $current + 1;
186                 continue;
187             }
188
189             if ($char === ' ') {
190                 if ($current - $lastStart >= $width) {
191                     $result    .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
192                     $lastStart  = $current + 1;
193                 }
194
195                 $lastSpace = $current;
196                 continue;
197             }
198
199             if ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
200                 $result    .= $this->substr($string, $lastStart, $current - $lastStart) . $break;
201                 $lastStart  = $lastSpace = $current;
202                 continue;
203             }
204
205             if ($current - $lastStart >= $width && $lastStart < $lastSpace) {
206                 $result    .= $this->substr($string, $lastStart, $lastSpace - $lastStart) . $break;
207                 $lastStart  = $lastSpace = $lastSpace + 1;
208                 continue;
209             }
210         }
211
212         if ($lastStart !== $current) {
213             $result .= $this->substr($string, $lastStart, $current - $lastStart);
214         }
215
216         return $result;
217     }
218
219     /**
220      * Pad a string to a certain length with another string
221      *
222      * @param  string  $input
223      * @param  int $padLength
224      * @param  string  $padString
225      * @param  int $padType
226      * @return string
227      */
228     public function strPad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT)
229     {
230         if (StringUtils::isSingleByteEncoding($this->getEncoding())) {
231             return str_pad($input, $padLength, $padString, $padType);
232         }
233
234         $lengthOfPadding = $padLength - $this->strlen($input);
235         if ($lengthOfPadding <= 0) {
236             return $input;
237         }
238
239         $padStringLength = $this->strlen($padString);
240         if ($padStringLength === 0) {
241             return $input;
242         }
243
244         $repeatCount = floor($lengthOfPadding / $padStringLength);
245
246         if ($padType === STR_PAD_BOTH) {
247             $repeatCountLeft = $repeatCountRight = ($repeatCount - $repeatCount % 2) / 2;
248
249             $lastStringLength       = $lengthOfPadding - 2 * $repeatCountLeft * $padStringLength;
250             $lastStringLeftLength   = $lastStringRightLength = floor($lastStringLength / 2);
251             $lastStringRightLength += $lastStringLength % 2;
252
253             $lastStringLeft  = $this->substr($padString, 0, $lastStringLeftLength);
254             $lastStringRight = $this->substr($padString, 0, $lastStringRightLength);
255
256             return str_repeat($padString, $repeatCountLeft) . $lastStringLeft
257                 . $input
258                 . str_repeat($padString, $repeatCountRight) . $lastStringRight;
259         }
260
261         $lastString = $this->substr($padString, 0, $lengthOfPadding % $padStringLength);
262
263         if ($padType === STR_PAD_LEFT) {
264             return str_repeat($padString, $repeatCount) . $lastString . $input;
265         }
266
267         return $input . str_repeat($padString, $repeatCount) . $lastString;
268     }
269 }