307 * leaks |
307 * leaks |
308 * |
308 * |
309 * @internal You should not use this directly from another application |
309 * @internal You should not use this directly from another application |
310 * |
310 * |
311 * @param string $hexString |
311 * @param string $hexString |
|
312 * @param string $ignore |
312 * @param bool $strictPadding |
313 * @param bool $strictPadding |
313 * @return string (raw binary) |
314 * @return string (raw binary) |
314 * @throws RangeException |
315 * @throws RangeException |
315 * @throws TypeError |
316 * @throws TypeError |
316 */ |
317 */ |
317 public static function hex2bin($hexString, $strictPadding = false) |
318 public static function hex2bin($hexString, $ignore = '', $strictPadding = false) |
318 { |
319 { |
319 /* Type checks: */ |
320 /* Type checks: */ |
320 if (!is_string($hexString)) { |
321 if (!is_string($hexString)) { |
321 throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.'); |
322 throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.'); |
322 } |
323 } |
323 |
324 if (!is_string($ignore)) { |
324 /** @var int $hex_pos */ |
325 throw new TypeError('Argument 2 must be a string, ' . gettype($hexString) . ' given.'); |
|
326 } |
|
327 |
325 $hex_pos = 0; |
328 $hex_pos = 0; |
326 /** @var string $bin */ |
|
327 $bin = ''; |
329 $bin = ''; |
328 /** @var int $c_acc */ |
|
329 $c_acc = 0; |
330 $c_acc = 0; |
330 /** @var int $hex_len */ |
|
331 $hex_len = self::strlen($hexString); |
331 $hex_len = self::strlen($hexString); |
332 /** @var int $state */ |
|
333 $state = 0; |
332 $state = 0; |
334 if (($hex_len & 1) !== 0) { |
333 if (($hex_len & 1) !== 0) { |
335 if ($strictPadding) { |
334 if ($strictPadding) { |
336 throw new RangeException( |
335 throw new RangeException( |
337 'Expected an even number of hexadecimal characters' |
336 'Expected an even number of hexadecimal characters' |
345 $chunk = unpack('C*', $hexString); |
344 $chunk = unpack('C*', $hexString); |
346 while ($hex_pos < $hex_len) { |
345 while ($hex_pos < $hex_len) { |
347 ++$hex_pos; |
346 ++$hex_pos; |
348 /** @var int $c */ |
347 /** @var int $c */ |
349 $c = $chunk[$hex_pos]; |
348 $c = $chunk[$hex_pos]; |
350 /** @var int $c_num */ |
|
351 $c_num = $c ^ 48; |
349 $c_num = $c ^ 48; |
352 /** @var int $c_num0 */ |
|
353 $c_num0 = ($c_num - 10) >> 8; |
350 $c_num0 = ($c_num - 10) >> 8; |
354 /** @var int $c_alpha */ |
|
355 $c_alpha = ($c & ~32) - 55; |
351 $c_alpha = ($c & ~32) - 55; |
356 /** @var int $c_alpha0 */ |
|
357 $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; |
352 $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; |
358 if (($c_num0 | $c_alpha0) === 0) { |
353 if (($c_num0 | $c_alpha0) === 0) { |
|
354 if ($ignore && $state === 0 && strpos($ignore, self::intToChr($c)) !== false) { |
|
355 continue; |
|
356 } |
359 throw new RangeException( |
357 throw new RangeException( |
360 'hex2bin() only expects hexadecimal characters' |
358 'hex2bin() only expects hexadecimal characters' |
361 ); |
359 ); |
362 } |
360 } |
363 /** @var int $c_val */ |
|
364 $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); |
361 $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); |
365 if ($state === 0) { |
362 if ($state === 0) { |
366 $c_acc = $c_val * 16; |
363 $c_acc = $c_val * 16; |
367 } else { |
364 } else { |
368 $bin .= pack('C', $c_acc | $c_val); |
365 $bin .= pack('C', $c_acc | $c_val); |
380 * @param array<int, int> $ints |
377 * @param array<int, int> $ints |
381 * @return string |
378 * @return string |
382 */ |
379 */ |
383 public static function intArrayToString(array $ints) |
380 public static function intArrayToString(array $ints) |
384 { |
381 { |
385 /** @var array<int, int> $args */ |
|
386 $args = $ints; |
382 $args = $ints; |
387 foreach ($args as $i => $v) { |
383 foreach ($args as $i => $v) { |
388 $args[$i] = (int) ($v & 0xff); |
384 $args[$i] = (int) ($v & 0xff); |
389 } |
385 } |
390 array_unshift($args, str_repeat('C', count($ints))); |
386 array_unshift($args, str_repeat('C', count($ints))); |