From 240985016495df026ba1b15caae0ab2a61457b45 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:40:28 +0200 Subject: [PATCH] Simplify CIDFontWidth parsing and allow multiple consecutive closing brackets --- .../DictionaryValue/Array/ArrayValue.php | 3 +- .../DictionaryValue/Array/CIDFontWidths.php | 37 ++++++++----------- .../DictionaryValue/Array/ArrayValueTest.php | 4 ++ .../Array/CIDFontWidthsTest.php | 15 ++++++++ 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/Document/Dictionary/DictionaryValue/Array/ArrayValue.php b/src/Document/Dictionary/DictionaryValue/Array/ArrayValue.php index 317f35c5..ce75484f 100644 --- a/src/Document/Dictionary/DictionaryValue/Array/ArrayValue.php +++ b/src/Document/Dictionary/DictionaryValue/Array/ArrayValue.php @@ -26,9 +26,10 @@ public static function fromValue(string $valueString): self|ReferenceValueArray| return null; } + $sanitizedValueString = substr($sanitizedValueString, 1, -1); $sanitizedValueString = preg_replace('/(<[^>]*>)(?=<[^>]*>)/', '$1 $2', $sanitizedValueString) ?? throw new RuntimeException('An error occurred while sanitizing array value'); - $sanitizedValueString = str_replace(['/', "\n"], [' /', ' '], rtrim(ltrim($sanitizedValueString, '[ '), ' ]')); + $sanitizedValueString = str_replace(['/', "\n"], [' /', ' '], $sanitizedValueString); $sanitizedValueString = preg_replace('/\s+/', ' ', $sanitizedValueString) ?? throw new RuntimeException('An error occurred while removing duplicate spaces from array value'); diff --git a/src/Document/Dictionary/DictionaryValue/Array/CIDFontWidths.php b/src/Document/Dictionary/DictionaryValue/Array/CIDFontWidths.php index 967339f5..a802a98d 100644 --- a/src/Document/Dictionary/DictionaryValue/Array/CIDFontWidths.php +++ b/src/Document/Dictionary/DictionaryValue/Array/CIDFontWidths.php @@ -6,7 +6,6 @@ use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Array\Item\ConsecutiveCIDWidth; use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Array\Item\RangeCIDWidth; use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\DictionaryValue; -use PrinsFrank\PdfParser\Exception\RuntimeException; /** @see 9.7.4.3 Glyph metrics in CIDFonts */ class CIDFontWidths implements DictionaryValue { @@ -37,37 +36,33 @@ public static function fromValue(string $valueString): ?self { return new self(); } - if (preg_match_all('/(?[0-9]+)\s*(?[0-9]+\s*[0-9.]+|\[[0-9. ]+\])/', $valueString, $matches, PREG_SET_ORDER) <= 0) { + if (($arrayValue = ArrayValue::fromValue($valueString)) instanceof ArrayValue === false) { return null; } $widths = []; - foreach ($matches as $match) { - if ((string) ($startingCID = (int) $match['startingCID']) !== $match['startingCID']) { + $nrOfTopLevelItems = count($arrayValue->value); + for ($i = 0; $i < $nrOfTopLevelItems; $i++) { + $item = $arrayValue->value[$i]; + if (is_int($item) === false) { return null; } - if (str_starts_with($match['CIDS'], '[') && str_ends_with($match['CIDS'], ']')) { - $cidWidths = preg_split('/\s+/', trim(rtrim(ltrim($match['CIDS'], '['), ']')), -1, PREG_SPLIT_NO_EMPTY); - if ($cidWidths === false) { - throw new RuntimeException('Something went wrong while splitting'); + if (($nextItem = $arrayValue->value[$i + 1] ?? null) instanceof ArrayValue) { + foreach ($nextItem->value as $itemValue) { + if (is_string($itemValue) === false && is_int($itemValue) === false) { + return null; + } } - $widths[] = new ConsecutiveCIDWidth($startingCID, array_map('floatval', $cidWidths)); - - continue; - } - - $arguments = explode(' ', $match['CIDS']); - if (count($arguments) !== 2) { + $widths[] = new ConsecutiveCIDWidth($item, array_map(fn(string|int $value) => is_string($value) ? (float) $value : $value, $nextItem->value)); + $i++; + } elseif (is_int($nextItem) && (is_string($secondNextItem = $arrayValue->value[$i + 2] ?? null) || is_int($secondNextItem))) { + $widths[] = new RangeCIDWidth($item, $nextItem, (float) $secondNextItem); + $i += 2; + } else { return null; } - - if ((string) ($endCID = (int) $arguments[0]) !== $arguments[0] || (string) ($width = (float) $arguments[1]) !== $arguments[1]) { - return null; - } - - $widths[] = new RangeCIDWidth($startingCID, $endCID, $width); } return new self(... $widths); diff --git a/tests/Unit/Document/Dictionary/DictionaryValue/Array/ArrayValueTest.php b/tests/Unit/Document/Dictionary/DictionaryValue/Array/ArrayValueTest.php index 635ead24..02f7e920 100644 --- a/tests/Unit/Document/Dictionary/DictionaryValue/Array/ArrayValueTest.php +++ b/tests/Unit/Document/Dictionary/DictionaryValue/Array/ArrayValueTest.php @@ -21,6 +21,10 @@ public function testFromValue(): void { new ArrayValue([42, 43]), ArrayValue::fromValue('[42 43]'), ); + static::assertEquals( + new ArrayValue([new ArrayValue([42, 43])]), + ArrayValue::fromValue('[[42 43]]'), + ); static::assertEquals( new ArrayValue([42, 43]), ArrayValue::fromValue(' [42 43] '), diff --git a/tests/Unit/Document/Dictionary/DictionaryValue/Array/CIDFontWidthsTest.php b/tests/Unit/Document/Dictionary/DictionaryValue/Array/CIDFontWidthsTest.php index 95cfac75..597de200 100644 --- a/tests/Unit/Document/Dictionary/DictionaryValue/Array/CIDFontWidthsTest.php +++ b/tests/Unit/Document/Dictionary/DictionaryValue/Array/CIDFontWidthsTest.php @@ -60,6 +60,21 @@ public function testFromValueWithPaddedBrackets(): void { ); } + public function testFromValueWithCompactBrackets(): void { + static::assertEquals( + new CIDFontWidths( + new ConsecutiveCIDWidth(3, [278]), + new ConsecutiveCIDWidth(18, [278]), + new ConsecutiveCIDWidth(46, [722]), + new ConsecutiveCIDWidth(72, [556]), + new ConsecutiveCIDWidth(80, [889]), + new RangeCIDWidth(81, 82, 611), + new ConsecutiveCIDWidth(88, [611]), + ), + CIDFontWidths::fromValue('[3[278] 18[278] 46[722] 72[556] 80[889] 81 82 611 88[611]]'), + ); + } + public function testFromValueAcceptsEmptyArray(): void { static::assertEquals( new CIDFontWidths(),