AutorÃa | Ultima modificación | Ver Log |
<?php
/**
* This file is part of FPDI
*
* @package setasign\Fpdi
* @copyright Copyright (c) 2023 Setasign GmbH & Co. KG (https://www.setasign.com)
* @license http://opensource.org/licenses/mit-license The MIT License
*/
namespace setasign\Fpdi\PdfParser\Type;
use setasign\Fpdi\PdfParser\StreamReader;
/**
* Class representing a PDF string object
*/
class PdfString extends PdfType
{
/**
* Parses a string object from the stream reader.
*
* @param StreamReader $streamReader
* @return self
*/
public static function parse(StreamReader $streamReader)
{
$pos = $startPos = $streamReader->getOffset();
$openBrackets = 1;
do {
$buffer = $streamReader->getBuffer(false);
for ($length = \strlen($buffer); $openBrackets !== 0 && $pos < $length; $pos++) {
switch ($buffer[$pos]) {
case '(':
$openBrackets++;
break;
case ')':
$openBrackets--;
break;
case '\\':
$pos++;
}
}
} while ($openBrackets !== 0 && $streamReader->increaseLength());
$result = \substr($buffer, $startPos, $openBrackets + $pos - $startPos - 1);
$streamReader->setOffset($pos);
$v = new self();
$v->value = $result;
return $v;
}
/**
* Helper method to create an instance.
*
* @param string $value The string needs to be escaped accordingly.
* @return self
*/
public static function create($value)
{
$v = new self();
$v->value = $value;
return $v;
}
/**
* Ensures that the passed value is a PdfString instance.
*
* @param mixed $string
* @return self
* @throws PdfTypeException
*/
public static function ensure($string)
{
return PdfType::ensureType(self::class, $string, 'String value expected.');
}
/**
* Escapes sequences in a string according to the PDF specification.
*
* @param string $s
* @return string
*/
public static function escape($s)
{
// Still a bit faster, than direct replacing
if (
\strpos($s, '\\') !== false ||
\strpos($s, ')') !== false ||
\strpos($s, '(') !== false ||
\strpos($s, "\x0D") !== false ||
\strpos($s, "\x0A") !== false ||
\strpos($s, "\x09") !== false ||
\strpos($s, "\x08") !== false ||
\strpos($s, "\x0C") !== false
) {
// is faster than strtr(...)
return \str_replace(
['\\', ')', '(', "\x0D", "\x0A", "\x09", "\x08", "\x0C"],
['\\\\', '\\)', '\\(', '\r', '\n', '\t', '\b', '\f'],
$s
);
}
return $s;
}
/**
* Unescapes escaped sequences in a PDF string according to the PDF specification.
*
* @param string $s
* @return string
*/
public static function unescape($s)
{
$out = '';
/** @noinspection ForeachInvariantsInspection */
for ($count = 0, $n = \strlen($s); $count < $n; $count++) {
if ($s[$count] !== '\\') {
$out .= $s[$count];
} else {
// A backslash at the end of the string - ignore it
if ($count === ($n - 1)) {
break;
}
switch ($s[++$count]) {
case ')':
case '(':
case '\\':
$out .= $s[$count];
break;
case 'f':
$out .= "\x0C";
break;
case 'b':
$out .= "\x08";
break;
case 't':
$out .= "\x09";
break;
case 'r':
$out .= "\x0D";
break;
case 'n':
$out .= "\x0A";
break;
case "\r":
if ($count !== $n - 1 && $s[$count + 1] === "\n") {
$count++;
}
break;
case "\n":
break;
default:
$actualChar = \ord($s[$count]);
// ascii 48 = number 0
// ascii 57 = number 9
if ($actualChar >= 48 && $actualChar <= 57) {
$oct = '' . $s[$count];
/** @noinspection NotOptimalIfConditionsInspection */
if (
$count + 1 < $n
&& \ord($s[$count + 1]) >= 48
&& \ord($s[$count + 1]) <= 57
) {
$count++;
$oct .= $s[$count];
/** @noinspection NotOptimalIfConditionsInspection */
if (
$count + 1 < $n
&& \ord($s[$count + 1]) >= 48
&& \ord($s[$count + 1]) <= 57
) {
$oct .= $s[++$count];
}
}
$out .= \chr(\octdec($oct));
} else {
// If the character is not one of those defined, the backslash is ignored
$out .= $s[$count];
}
}
}
}
return $out;
}
}