From 25e5a5273bc53833e8eb5616685bb3fd358054e8 Mon Sep 17 00:00:00 2001 From: mondrake Date: Sun, 11 Feb 2024 16:11:40 +0100 Subject: [PATCH] Dev 240211 (#81) --- .github/workflows/tests.yml | 4 +- composer.json | 11 +++- specs/Jpeg/Exif.yaml | 2 + specs/Jpeg/Segment.yaml | 2 + specs/Jpeg/SegmentApp1.yaml | 2 + specs/Jpeg/SegmentCom.yaml | 2 + specs/Jpeg/SegmentSos.yaml | 2 + .../Exif/Vendor/Canon/FilterInfoIndex.php | 16 ++--- src/Block/Jpeg/Exif.php | 46 --------------- src/Block/Jpeg/Segment.php | 12 ---- src/Block/Jpeg/SegmentApp1.php | 23 -------- src/Block/Jpeg/SegmentCom.php | 13 ----- src/Block/Jpeg/SegmentSos.php | 49 ---------------- src/Collection/Jpeg/Exif.php | 2 + src/Collection/Jpeg/Segment.php | 2 + src/Collection/Jpeg/SegmentApp1.php | 2 + src/Collection/Jpeg/SegmentCom.php | 2 + src/Collection/Jpeg/SegmentSos.php | 2 + src/ItemDefinition.php | 39 +++++++++---- src/Media.php | 3 +- src/Parser/Jpeg/Exif.php | 56 ++++++++++++++++++ src/Parser/Jpeg/Segment.php | 20 +++++++ src/Parser/Jpeg/SegmentApp1.php | 31 ++++++++++ src/Parser/Jpeg/SegmentCom.php | 21 +++++++ src/Parser/Jpeg/SegmentSos.php | 58 +++++++++++++++++++ src/Parser/ParserBase.php | 8 ++- src/Parser/Tiff/Tiff.php | 1 - 27 files changed, 260 insertions(+), 171 deletions(-) create mode 100644 src/Parser/Jpeg/Exif.php create mode 100644 src/Parser/Jpeg/Segment.php create mode 100644 src/Parser/Jpeg/SegmentApp1.php create mode 100644 src/Parser/Jpeg/SegmentCom.php create mode 100644 src/Parser/Jpeg/SegmentSos.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a4e773359..302f75ce0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,9 +15,9 @@ jobs: fail-fast: false matrix: php-version: -# - "8.1" + - "8.1" - "8.2" -# - "8.3" + - "8.3" steps: - name: Install PHP diff --git a/composer.json b/composer.json index 14cf692e7..3412f489e 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,9 @@ "symfony/var-dumper": "^6 | ^7", "symfony/yaml": "^6 | ^7", "bramus/monolog-colored-line-formatter": "^3", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.10", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan-deprecation-rules": "^1.1" }, "autoload": { "psr-4": { @@ -41,5 +43,10 @@ "FileEye\\MediaProbe\\Test\\": "tests/" } }, - "bin": ["bin/fileeye-mediaprobe"] + "bin": ["bin/fileeye-mediaprobe"], + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } + } } diff --git a/specs/Jpeg/Exif.yaml b/specs/Jpeg/Exif.yaml index 59a9e862e..9b3826830 100644 --- a/specs/Jpeg/Exif.yaml +++ b/specs/Jpeg/Exif.yaml @@ -1,6 +1,8 @@ collection: Jpeg\Exif title: 'JPEG Exif data' class: FileEye\MediaProbe\Block\Jpeg\Exif +parser: FileEye\MediaProbe\Parser\Jpeg\Exif +writer: FileEye\MediaProbe\Writer\Jpeg\Exif DOMNode: exif items: Tiff: diff --git a/specs/Jpeg/Segment.yaml b/specs/Jpeg/Segment.yaml index 072be861b..000f10f3b 100644 --- a/specs/Jpeg/Segment.yaml +++ b/specs/Jpeg/Segment.yaml @@ -1,5 +1,7 @@ collection: Jpeg\Segment title: Generic JPEG data segment class: FileEye\MediaProbe\Block\Jpeg\Segment +parser: FileEye\MediaProbe\Parser\Jpeg\Segment +writer: FileEye\MediaProbe\Writer\Jpeg\Segment DOMNode: jpegSegment items: {} diff --git a/specs/Jpeg/SegmentApp1.yaml b/specs/Jpeg/SegmentApp1.yaml index 89ede9e20..a79436cfe 100644 --- a/specs/Jpeg/SegmentApp1.yaml +++ b/specs/Jpeg/SegmentApp1.yaml @@ -3,6 +3,8 @@ name: APP1 title: 'JPEG Application segment 1' payload: variable class: FileEye\MediaProbe\Block\Jpeg\SegmentApp1 +parser: FileEye\MediaProbe\Parser\Jpeg\SegmentApp1 +writer: FileEye\MediaProbe\Writer\Jpeg\SegmentApp1 DOMNode: jpegSegment items: Exif: diff --git a/specs/Jpeg/SegmentCom.yaml b/specs/Jpeg/SegmentCom.yaml index e1ce52afb..ca01168a1 100644 --- a/specs/Jpeg/SegmentCom.yaml +++ b/specs/Jpeg/SegmentCom.yaml @@ -3,5 +3,7 @@ name: COM title: 'JPEG Comment' payload: variable class: FileEye\MediaProbe\Block\Jpeg\SegmentCom +parser: FileEye\MediaProbe\Parser\Jpeg\SegmentCom +writer: FileEye\MediaProbe\Writer\Jpeg\SegmentCom DOMNode: jpegSegment items: {} diff --git a/specs/Jpeg/SegmentSos.yaml b/specs/Jpeg/SegmentSos.yaml index 44adb511c..3c8b5be7f 100644 --- a/specs/Jpeg/SegmentSos.yaml +++ b/specs/Jpeg/SegmentSos.yaml @@ -3,5 +3,7 @@ name: SOS title: 'JPEG Start of scan' payload: scan class: FileEye\MediaProbe\Block\Jpeg\SegmentSos +parser: FileEye\MediaProbe\Parser\Jpeg\SegmentSos +writer: FileEye\MediaProbe\Writer\Jpeg\SegmentSos DOMNode: jpegSegment items: {} diff --git a/src/Block/Exif/Vendor/Canon/FilterInfoIndex.php b/src/Block/Exif/Vendor/Canon/FilterInfoIndex.php index f9c9b27f8..7d0b4f12c 100644 --- a/src/Block/Exif/Vendor/Canon/FilterInfoIndex.php +++ b/src/Block/Exif/Vendor/Canon/FilterInfoIndex.php @@ -57,13 +57,15 @@ protected function doParseData(DataElement $data): void $filter_size = $data->getLong($offset + 4); $this ->addBlock( - new ItemDefinition(CollectionFactory::get('ExifMakerNotes\Canon\Filter'), - DataFormat::BYTE, - $filter_size, - $offset, - 0, - $i - )) + new ItemDefinition( + CollectionFactory::get('ExifMakerNotes\Canon\Filter'), + DataFormat::BYTE, + $filter_size, + $offset, + 0, + $i + ) + ) ->parseData(new DataWindow($data, $offset, $filter_size + 4)); $offset += 4 + $filter_size; } diff --git a/src/Block/Jpeg/Exif.php b/src/Block/Jpeg/Exif.php index 823c7c060..654fb7a4f 100644 --- a/src/Block/Jpeg/Exif.php +++ b/src/Block/Jpeg/Exif.php @@ -3,12 +3,6 @@ namespace FileEye\MediaProbe\Block\Jpeg; use FileEye\MediaProbe\Model\BlockBase; -use FileEye\MediaProbe\Collection\CollectionFactory; -use FileEye\MediaProbe\Data\DataElement; -use FileEye\MediaProbe\Data\DataWindow; -use FileEye\MediaProbe\Entry\Core\Undefined; -use FileEye\MediaProbe\ItemDefinition; -use FileEye\MediaProbe\MediaProbe; use FileEye\MediaProbe\Utility\ConvertBytes; /** @@ -27,28 +21,6 @@ class Exif extends BlockBase // @todo xxx the trailing bytes may not be zeros const EXIF_HEADER = "Exif\0\0"; - /** - * {@inheritdoc} - */ - protected function doParseData(DataElement $data): void - { - assert($this->debugInfo(['dataElement' => $data])); - - $tiff = new ItemDefinition( - collection: CollectionFactory::get('Tiff\Tiff'), - ); - $tiffParser = $tiff->collection->getPropertyValue('parser'); - - if ($tiffParser::getTiffSegmentByteOrder($data, strlen(self::EXIF_HEADER)) !== null) { - $this->addBlock($tiff)->parseData($data, strlen(self::EXIF_HEADER), $data->getSize() - strlen(self::EXIF_HEADER)); - } else { - // We store the data as normal JPEG content if it could not be - // parsed as Tiff data. - $entry = new Undefined($this, [$data->getBytes()]); - $this->error("TIFF header not found. Parsed {text}", ['text' => $entry->toString()]); - } - } - /** * {@inheritdoc} */ @@ -56,22 +28,4 @@ public function toBytes(int $byte_order = ConvertBytes::LITTLE_ENDIAN, int $offs { return self::EXIF_HEADER . $this->getElement('*')->toBytes(); } - - /** - * Determines if the data is an EXIF segment. - */ - public static function isExifSegment(DataElement $dataElement, $offset = 0): bool - { - // There must be at least 6 bytes for the Exif header. - if ($dataElement->getSize() - $offset < strlen(self::EXIF_HEADER)) { - return false; - } - - // Verify the Exif header. - if ($dataElement->getBytes($offset, strlen(self::EXIF_HEADER)) === self::EXIF_HEADER) { - return true; - } - - return false; - } } diff --git a/src/Block/Jpeg/Segment.php b/src/Block/Jpeg/Segment.php index 1bfbe0c20..133669023 100644 --- a/src/Block/Jpeg/Segment.php +++ b/src/Block/Jpeg/Segment.php @@ -2,9 +2,6 @@ namespace FileEye\MediaProbe\Block\Jpeg; -use FileEye\MediaProbe\Data\DataElement; -use FileEye\MediaProbe\Entry\Core\Undefined; - /** * Class representing a generic JPEG data segment. * @@ -12,13 +9,4 @@ */ class Segment extends SegmentBase { - /** - * {@inheritdoc} - */ - protected function doParseData(DataElement $data): void - { - assert($this->debugInfo(['dataElement' => $data])); - // Adds the segment data as an Undefined entry. - new Undefined($this, $data); - } } diff --git a/src/Block/Jpeg/SegmentApp1.php b/src/Block/Jpeg/SegmentApp1.php index edcb2983e..6cb48624b 100644 --- a/src/Block/Jpeg/SegmentApp1.php +++ b/src/Block/Jpeg/SegmentApp1.php @@ -2,11 +2,6 @@ namespace FileEye\MediaProbe\Block\Jpeg; -use FileEye\MediaProbe\Block\Jpeg\Exif; -use FileEye\MediaProbe\Collection\CollectionFactory; -use FileEye\MediaProbe\Data\DataElement; -use FileEye\MediaProbe\Entry\Core\Undefined; -use FileEye\MediaProbe\ItemDefinition; use FileEye\MediaProbe\Utility\ConvertBytes; /** @@ -14,24 +9,6 @@ */ class SegmentApp1 extends SegmentBase { - /** - * {@inheritdoc} - */ - protected function doParseData(DataElement $data): void - { - assert($this->debugInfo(['dataElement' => $data])); - // If we have an Exif table, parse it. - if (Exif::isExifSegment($data, 4)) { - $exif = new ItemDefinition(CollectionFactory::get('Jpeg\Exif')); - $this->addBlock($exif)->parseData($data, 4, $data->getSize() - 4); - } else { - // We store the data as normal JPEG content if it could not be - // parsed as Exif data. - $entry = new Undefined($this, $data); - $entry->debug("Not an Exif segment. Parsed {text}", ['text' => $entry->toString()]); - } - } - /** * {@inheritdoc} */ diff --git a/src/Block/Jpeg/SegmentCom.php b/src/Block/Jpeg/SegmentCom.php index 8c3e164bc..dd9b39bbf 100644 --- a/src/Block/Jpeg/SegmentCom.php +++ b/src/Block/Jpeg/SegmentCom.php @@ -2,9 +2,6 @@ namespace FileEye\MediaProbe\Block\Jpeg; -use FileEye\MediaProbe\Data\DataElement; -use FileEye\MediaProbe\Data\DataWindow; -use FileEye\MediaProbe\Entry\Core\Char; use FileEye\MediaProbe\Utility\ConvertBytes; /** @@ -12,16 +9,6 @@ */ class SegmentCom extends SegmentBase { - /** - * {@inheritdoc} - */ - protected function doParseData(DataElement $data): void - { - assert($this->debugInfo(['dataElement' => $data])); - // Adds the segment data as a Char string. - new Char($this, new DataWindow($data, 4)); - } - /** * {@inheritdoc} */ diff --git a/src/Block/Jpeg/SegmentSos.php b/src/Block/Jpeg/SegmentSos.php index 0e291dc27..0cfe072c4 100644 --- a/src/Block/Jpeg/SegmentSos.php +++ b/src/Block/Jpeg/SegmentSos.php @@ -2,14 +2,6 @@ namespace FileEye\MediaProbe\Block\Jpeg; -use FileEye\MediaProbe\Block\RawData; -use FileEye\MediaProbe\Collection\CollectionFactory; -use FileEye\MediaProbe\Data\DataElement; -use FileEye\MediaProbe\Data\DataWindow; -use FileEye\MediaProbe\Entry\Core\Undefined; -use FileEye\MediaProbe\ItemDefinition; -use FileEye\MediaProbe\Data\DataFormat; - /** * Class representing a JPEG SOS segment. */ @@ -19,45 +11,4 @@ class SegmentSos extends SegmentBase * JPEG EOI marker. */ const JPEG_EOI = 0xD9; - - /** - * {@inheritdoc} - */ - protected function doParseData(DataElement $data): void - { - assert($this->debugInfo(['dataElement' => $data])); - // This segment is last before End Of Image, and its length needs to be - // determined by finding the EOI marker backwards from the end of data. - // Some images have some trailing (garbage?) following the EOI marker, - // which we store in a RawData object. - $scan_size = $data->getSize(); - while ($data->getByte($scan_size - 2) !== Jpeg::JPEG_DELIMITER || $data->getByte($scan_size - 1) != self::JPEG_EOI) { - $scan_size --; - } - $scan_size -= 2; - - // Load data in an Undefined entry. - $data_window = new DataWindow($data, 0, $scan_size); - new Undefined($this, $data_window); - - // Append the EOI. - $end_offset = $scan_size; - $eoi = new ItemDefinition( - $this->getParentElement()->getCollection()->getItemCollection(self::JPEG_EOI) - ); - $this->getParentElement()->addBlock($eoi)->parseData($data, $end_offset, 2); - $end_offset += 2; - - // Now check to see if there are any trailing data. - if ($end_offset < $data->getSize()) { - $raw_size = $data->getSize() - $end_offset; - $this->warning('Found trailing content after EOI: {size} bytes', ['size' => $raw_size]); - // There is no JPEG marker for trailing garbage, so we just collect - // the data in a RawData object. - $trail_definition = new ItemDefinition(CollectionFactory::get('RawData'), DataFormat::BYTE, $raw_size); - $trail_data_window = new DataWindow($data, $end_offset, $raw_size); - $trail = new RawData($trail_definition, $this->getParentElement()); - $trail->parseData($trail_data_window); - } - } } diff --git a/src/Collection/Jpeg/Exif.php b/src/Collection/Jpeg/Exif.php index ef7593b9d..2c3db34fd 100644 --- a/src/Collection/Jpeg/Exif.php +++ b/src/Collection/Jpeg/Exif.php @@ -15,6 +15,8 @@ class Exif extends CollectionBase { protected static $map = array ( 'title' => 'JPEG Exif data', 'class' => 'FileEye\\MediaProbe\\Block\\Jpeg\\Exif', + 'parser' => 'FileEye\\MediaProbe\\Parser\\Jpeg\\Exif', + 'writer' => 'FileEye\\MediaProbe\\Writer\\Jpeg\\Exif', 'DOMNode' => 'exif', 'id' => 'Jpeg\\Exif', 'items' => diff --git a/src/Collection/Jpeg/Segment.php b/src/Collection/Jpeg/Segment.php index 81312ceba..e6dca801b 100644 --- a/src/Collection/Jpeg/Segment.php +++ b/src/Collection/Jpeg/Segment.php @@ -15,6 +15,8 @@ class Segment extends CollectionBase { protected static $map = array ( 'title' => 'Generic JPEG data segment', 'class' => 'FileEye\\MediaProbe\\Block\\Jpeg\\Segment', + 'parser' => 'FileEye\\MediaProbe\\Parser\\Jpeg\\Segment', + 'writer' => 'FileEye\\MediaProbe\\Writer\\Jpeg\\Segment', 'DOMNode' => 'jpegSegment', 'id' => 'Jpeg\\Segment', ); diff --git a/src/Collection/Jpeg/SegmentApp1.php b/src/Collection/Jpeg/SegmentApp1.php index 1ecc609b1..ec9cf310a 100644 --- a/src/Collection/Jpeg/SegmentApp1.php +++ b/src/Collection/Jpeg/SegmentApp1.php @@ -17,6 +17,8 @@ class SegmentApp1 extends CollectionBase { 'title' => 'JPEG Application segment 1', 'payload' => 'variable', 'class' => 'FileEye\\MediaProbe\\Block\\Jpeg\\SegmentApp1', + 'parser' => 'FileEye\\MediaProbe\\Parser\\Jpeg\\SegmentApp1', + 'writer' => 'FileEye\\MediaProbe\\Writer\\Jpeg\\SegmentApp1', 'DOMNode' => 'jpegSegment', 'id' => 'Jpeg\\SegmentApp1', 'items' => diff --git a/src/Collection/Jpeg/SegmentCom.php b/src/Collection/Jpeg/SegmentCom.php index 4d2c88d9f..f6413959f 100644 --- a/src/Collection/Jpeg/SegmentCom.php +++ b/src/Collection/Jpeg/SegmentCom.php @@ -17,6 +17,8 @@ class SegmentCom extends CollectionBase { 'title' => 'JPEG Comment', 'payload' => 'variable', 'class' => 'FileEye\\MediaProbe\\Block\\Jpeg\\SegmentCom', + 'parser' => 'FileEye\\MediaProbe\\Parser\\Jpeg\\SegmentCom', + 'writer' => 'FileEye\\MediaProbe\\Writer\\Jpeg\\SegmentCom', 'DOMNode' => 'jpegSegment', 'id' => 'Jpeg\\SegmentCom', ); diff --git a/src/Collection/Jpeg/SegmentSos.php b/src/Collection/Jpeg/SegmentSos.php index 7fec4249a..eb00b4925 100644 --- a/src/Collection/Jpeg/SegmentSos.php +++ b/src/Collection/Jpeg/SegmentSos.php @@ -17,6 +17,8 @@ class SegmentSos extends CollectionBase { 'title' => 'JPEG Start of scan', 'payload' => 'scan', 'class' => 'FileEye\\MediaProbe\\Block\\Jpeg\\SegmentSos', + 'parser' => 'FileEye\\MediaProbe\\Parser\\Jpeg\\SegmentSos', + 'writer' => 'FileEye\\MediaProbe\\Writer\\Jpeg\\SegmentSos', 'DOMNode' => 'jpegSegment', 'id' => 'Jpeg\\SegmentSos', ); diff --git a/src/ItemDefinition.php b/src/ItemDefinition.php index cfa415bb4..b2bebf800 100644 --- a/src/ItemDefinition.php +++ b/src/ItemDefinition.php @@ -26,40 +26,57 @@ class ItemDefinition */ public function __construct( public readonly CollectionInterface $collection, - protected int $format = DataFormat::BYTE, - protected int $valuesCount = 1, - protected int $dataOffset = 0, - protected int $itemDefinitionOffset = 0, - protected int $sequence = 0, - ) - { + public readonly int $format = DataFormat::BYTE, + public readonly int $valuesCount = 1, + public readonly int $dataOffset = 0, + public readonly int $itemDefinitionOffset = 0, + public readonly int $sequence = 0, + ) { } + /** + * @deprecated + */ public function getCollection(): CollectionInterface { return $this->collection; } + /** + * @deprecated + */ public function getFormat(): int { return $this->format; } + /** + * @deprecated + */ public function getValuesCount(): int { return $this->valuesCount; } + /** + * @deprecated + */ public function getDataOffset(): int { return $this->dataOffset; } + /** + * @deprecated + */ public function getItemDefinitionOffset(): int { return $this->itemDefinitionOffset; } + /** + * @deprecated + */ public function getSequence(): int { return $this->sequence; @@ -70,7 +87,7 @@ public function getSequence(): int */ public function getSize(): int { - return DataFormat::getSize($this->getFormat()) * $this->getValuesCount(); + return DataFormat::getSize($this->format) * $this->valuesCount; } /** @@ -82,7 +99,7 @@ public function getEntryClass(): string // Return the specific entry class if defined, or fall back to // default class for the format. if (!$entry_class = $this->collection->getPropertyValue('entryClass')) { - if (empty($this->getFormat())) { + if (empty($this->format)) { throw new MediaProbeException( 'No format can be derived for item: %s (%s)', $this->collection->getPropertyValue('item') ?? 'n/a', @@ -90,10 +107,10 @@ public function getEntryClass(): string ); } - if (!$entry_class = DataFormat::getClass($this->getFormat())) { + if (!$entry_class = DataFormat::getClass($this->format)) { throw new MediaProbeException( 'Unsupported format %d for item: %s (%s)', - $this->getFormat(), + $this->format, $this->collection->getPropertyValue('item') ?? 'n/a', $this->collection->getPropertyValue('name') ?? 'n/a' ); diff --git a/src/Media.php b/src/Media.php index db0fc1a00..fee535d65 100644 --- a/src/Media.php +++ b/src/Media.php @@ -64,8 +64,7 @@ class Media extends RootBlockBase public function __construct( protected ?LoggerInterface $externalLogger, ?string $failLevel, - ) - { + ) { $media = new ItemDefinition(CollectionFactory::get('Media')); parent::__construct($media); $this->logger = (new Logger('mediaprobe')) diff --git a/src/Parser/Jpeg/Exif.php b/src/Parser/Jpeg/Exif.php new file mode 100644 index 000000000..32d0ae171 --- /dev/null +++ b/src/Parser/Jpeg/Exif.php @@ -0,0 +1,56 @@ +block->debugInfo(['dataElement' => $data])); + + $tiff = new ItemDefinition( + collection: CollectionFactory::get('Tiff\Tiff'), + ); + $tiffParser = $tiff->collection->getPropertyValue('parser'); + + if ($tiffParser::getTiffSegmentByteOrder($data, strlen(ExifBlock::EXIF_HEADER)) !== null) { + $this->block->addBlock($tiff)->parseData($data, strlen(ExifBlock::EXIF_HEADER), $data->getSize() - strlen(ExifBlock::EXIF_HEADER)); + } else { + // We store the data as normal JPEG content if it could not be + // parsed as Tiff data. + $entry = new Undefined($this->block, [$data->getBytes()]); + $this->block->error("TIFF header not found. Parsed {text}", ['text' => $entry->toString()]); + } + } + + /** + * Determines if the data is an EXIF segment. + */ + public static function isExifSegment(DataElement $dataElement, $offset = 0): bool + { + // There must be at least 6 bytes for the Exif header. + if ($dataElement->getSize() - $offset < strlen(ExifBlock::EXIF_HEADER)) { + return false; + } + + // Verify the Exif header. + if ($dataElement->getBytes($offset, strlen(ExifBlock::EXIF_HEADER)) === ExifBlock::EXIF_HEADER) { + return true; + } + + return false; + } +} diff --git a/src/Parser/Jpeg/Segment.php b/src/Parser/Jpeg/Segment.php new file mode 100644 index 000000000..06fbc1d64 --- /dev/null +++ b/src/Parser/Jpeg/Segment.php @@ -0,0 +1,20 @@ +block->debugInfo(['dataElement' => $data])); + // Adds the segment data as an Undefined entry. + new Undefined($this->block, $data); + } +} diff --git a/src/Parser/Jpeg/SegmentApp1.php b/src/Parser/Jpeg/SegmentApp1.php new file mode 100644 index 000000000..17eeeefcb --- /dev/null +++ b/src/Parser/Jpeg/SegmentApp1.php @@ -0,0 +1,31 @@ +block->debugInfo(['dataElement' => $data])); + // If we have an Exif table, parse it. + // @todo use parser and not class call driectly + if (Exif::isExifSegment($data, 4)) { + $exif = new ItemDefinition(CollectionFactory::get('Jpeg\Exif')); + $this->block->addBlock($exif)->parseData($data, 4, $data->getSize() - 4); + } else { + // We store the data as normal JPEG content if it could not be + // parsed as Exif data. + $entry = new Undefined($this->block, $data); + $entry->debug("Not an Exif segment. Parsed {text}", ['text' => $entry->toString()]); + } + } +} diff --git a/src/Parser/Jpeg/SegmentCom.php b/src/Parser/Jpeg/SegmentCom.php new file mode 100644 index 000000000..d75c9e060 --- /dev/null +++ b/src/Parser/Jpeg/SegmentCom.php @@ -0,0 +1,21 @@ +block->debugInfo(['dataElement' => $data])); + // Adds the segment data as a Char string. + new Char($this->block, new DataWindow($data, 4)); + } +} diff --git a/src/Parser/Jpeg/SegmentSos.php b/src/Parser/Jpeg/SegmentSos.php new file mode 100644 index 000000000..5fa9411ac --- /dev/null +++ b/src/Parser/Jpeg/SegmentSos.php @@ -0,0 +1,58 @@ +block->debugInfo(['dataElement' => $data])); + // This segment is last before End Of Image, and its length needs to be + // determined by finding the EOI marker backwards from the end of data. + // Some images have some trailing (garbage?) following the EOI marker, + // which we store in a RawData object. + $scan_size = $data->getSize(); + while ($data->getByte($scan_size - 2) !== JpegBlock::JPEG_DELIMITER || $data->getByte($scan_size - 1) != SegmentSosBlock::JPEG_EOI) { + $scan_size --; + } + $scan_size -= 2; + + // Load data in an Undefined entry. + $data_window = new DataWindow($data, 0, $scan_size); + new Undefined($this->block, $data_window); + + // Append the EOI. + $end_offset = $scan_size; + $eoi = new ItemDefinition( + $this->block->getParentElement()->getCollection()->getItemCollection(SegmentSosBlock::JPEG_EOI) + ); + $this->block->getParentElement()->addBlock($eoi)->parseData($data, $end_offset, 2); + $end_offset += 2; + + // Now check to see if there are any trailing data. + if ($end_offset < $data->getSize()) { + $raw_size = $data->getSize() - $end_offset; + $this->block->warning('Found trailing content after EOI: {size} bytes', ['size' => $raw_size]); + // There is no JPEG marker for trailing garbage, so we just collect + // the data in a RawData object. + $trail_definition = new ItemDefinition(CollectionFactory::get('RawData'), DataFormat::BYTE, $raw_size); + $trail_data_window = new DataWindow($data, $end_offset, $raw_size); + $trail = new RawData($trail_definition, $this->block->getParentElement()); + $trail->parseData($trail_data_window); + } + } +} diff --git a/src/Parser/ParserBase.php b/src/Parser/ParserBase.php index c1c484351..fe7a6f8ba 100644 --- a/src/Parser/ParserBase.php +++ b/src/Parser/ParserBase.php @@ -2,13 +2,15 @@ namespace FileEye\MediaProbe\Parser; +use FileEye\MediaProbe\Data\DataElement; use FileEye\MediaProbe\Model\BlockInterface; -class ParserBase +abstract class ParserBase { public function __construct( protected readonly BlockInterface $block, - ) - { + ) { } + + abstract public function parseData(DataElement $data): void; } diff --git a/src/Parser/Tiff/Tiff.php b/src/Parser/Tiff/Tiff.php index 30bec330a..1ec3a8952 100644 --- a/src/Parser/Tiff/Tiff.php +++ b/src/Parser/Tiff/Tiff.php @@ -139,5 +139,4 @@ public static function getTiffSegmentByteOrder(DataElement $dataElement, int $of return $order; } - }