1<?php
2declare(strict_types=1);
3
4namespace PrinsFrank\PdfParser\Document\Generic\Character;
5
6use PrinsFrank\PdfParser\Exception\ParseFailureException;
7
8/**
9 * @internal
10 *
11 * @see Pdf 32000-1:2008 7.3.4.2 Table 3
12 */
13enum LiteralStringEscapeCharacter: string {
14    case LINE_FEED = '\n';
15    case CARRIAGE_RETURN = '\r';
16    case HORIZONTAL_TAB = '\t';
17    case BACKSPACE = '\b';
18    case FORM_FEED = '\f';
19    case LEFT_PARENTHESIS = '\(';
20    case RIGHT_PARENTHESIS = '\)';
21    case REVERSE_SOLIDUS = '\\';
22
23    public static function unescapeCharacters(string $string): string {
24        $string = str_replace("\\\n", '', $string); // Example 2, 7.3.4.2 newlines preceded by reverse solidus should be handled like single lines
25
26        return preg_replace_callback(
27            '/\\\\([0-7]{1,3})/',
28            static function (array $matches) {
29                $decimal = octdec($matches[1]);
30                if (!is_int($decimal) || $decimal < 0 || $decimal > 255) {
31                    throw new ParseFailureException(sprintf('Invalid octal value "%s"', $matches[1]));
32                }
33
34                return mb_chr($decimal);
35            },
36            str_replace(['\n', '\r', '\t', '\b', '\f', '\(', '\)', '\\'], ["\n", "\r", "\t", "\x08", "\x0C", "(", ")", "\\"], $string),
37        ) ?? throw new ParseFailureException();
38    }
39}
40