diff --git a/src/Block/Jpeg/Jpeg.php b/src/Block/Jpeg/Jpeg.php index 0908a39fc..6df3ba228 100644 --- a/src/Block/Jpeg/Jpeg.php +++ b/src/Block/Jpeg/Jpeg.php @@ -4,12 +4,14 @@ use FileEye\MediaProbe\Block\RawData; use FileEye\MediaProbe\Collection\CollectionFactory; +use FileEye\MediaProbe\Collection\CollectionInterface; use FileEye\MediaProbe\Data\DataElement; use FileEye\MediaProbe\Data\DataException; use FileEye\MediaProbe\Data\DataFormat; use FileEye\MediaProbe\ItemDefinition; use FileEye\MediaProbe\Model\BlockBase; use FileEye\MediaProbe\Model\MediaTypeBlockInterface; +use FileEye\MediaProbe\Model\RootBlockBase; use FileEye\MediaProbe\Utility\ConvertBytes; /** @@ -27,12 +29,19 @@ class Jpeg extends BlockBase implements MediaTypeBlockInterface */ const JPEG_HEADER = "\xFF\xD8\xFF"; + public function __construct( + protected CollectionInterface $collection, + RootBlockBase $parent, + ) { + parent::__construct(new ItemDefinition($collection), $parent, null, false); + } + public static function isDataMatchingMediaType(DataElement $dataElement): bool { return $dataElement->getBytes(0, 3) === static::JPEG_HEADER; } - public function doParseData(DataElement $data): void + public function fromDataElement(DataElement $data): Jpeg { assert($this->debugInfo(['dataElement' => $data])); @@ -69,7 +78,7 @@ public function doParseData(DataElement $data): void $offset = $newOffset; } catch (DataException $e) { $this->error($e->getMessage()); - return; + return $this; } // Get the JPEG segment id. @@ -119,6 +128,8 @@ public function doParseData(DataElement $data): void if (!$this->getElement("jpegSegment[@name='EOI']")) { $this->error('Missing EOI (End Of Image) JPEG marker'); } + + return $this; } /** diff --git a/src/Media.php b/src/Media.php index 27f5099e6..3d6e15026 100644 --- a/src/Media.php +++ b/src/Media.php @@ -61,12 +61,6 @@ public static function createFromFile( return $media; } - /** - * Creates a Media object from data. - * - * @param DataElement $dataElement - * The data element providing the data. - */ public function fromDataElement(DataElement $dataElement): Media { $this->getStopwatch()->start('media-parsing'); @@ -79,8 +73,12 @@ public function fromDataElement(DataElement $dataElement): Media // Build the Media immediate child object, that represents the actual media. Then // parse the media according to the media format. $mediaTypeHandler = $mediaTypeCollection->getHandler(); - $mediaTypeBlock = new $mediaTypeHandler(new ItemDefinition($mediaTypeCollection), $this); - $mediaTypeBlock->parseData($dataElement); + $mediaTypeBlock = new $mediaTypeHandler( + collection: $mediaTypeCollection, + parent: $this, + ); + $mediaTypeBlock->fromDataElement($dataElement); + $this->graftBlock($mediaTypeBlock); $this->level = $mediaTypeBlock->level(); } catch (MediaProbeException $e) { assert($this->debugInfo(['dataElement' => $dataElement])); @@ -92,6 +90,11 @@ public function fromDataElement(DataElement $dataElement): Media return $this; } + public function graftBlock($mediaTypeBlock): void + { + $this->DOMNode->appendChild($mediaTypeBlock->DOMNode); + } + /** * Save the Media object as a file. * diff --git a/src/Model/BlockBase.php b/src/Model/BlockBase.php index bb18d9286..94f58a884 100644 --- a/src/Model/BlockBase.php +++ b/src/Model/BlockBase.php @@ -45,13 +45,14 @@ public function __construct( ItemDefinition $definition, ?BlockInterface $parent = null, ?BlockInterface $reference = null, + bool $graft = TRUE, ) { $this->definition = $definition; - parent::__construct($this->getCollection()->getPropertyValue('DOMNode'), $parent, $reference); + parent::__construct($this->getCollection()->getPropertyValue('DOMNode'), $parent, $reference, $graft); if (!isset($this->DOMNode)) { - return; + throw new MediaProbeException(sprintf('No DOM node specified for %s', __CLASS__)); } if ($this->getCollection()->hasProperty('item')) { @@ -111,6 +112,11 @@ public function parseData(DataElement $dataElement, int $start = 0, ?int $size = $this->executePostParseCallbacks($data); } + public function fromDataElement(DataElement $dataElement): BlockInterface + { + throw new \LogicException(sprintf('%s does not implement %s()', get_class($this), 'fromDataElement')); + } + /** * Invoke post-parse callbacks. * diff --git a/src/Model/BlockInterface.php b/src/Model/BlockInterface.php index 5ba328a3b..09987857e 100644 --- a/src/Model/BlockInterface.php +++ b/src/Model/BlockInterface.php @@ -22,4 +22,6 @@ public function getDefinition(): ItemDefinition; public function getCollection(): CollectionInterface; public function parseData(DataElement $dataElement, int $start = 0, ?int $size = null): void; + + public function fromDataElement(DataElement $dataElement): BlockInterface; } diff --git a/src/Model/ElementBase.php b/src/Model/ElementBase.php index b67487088..2ad62519e 100644 --- a/src/Model/ElementBase.php +++ b/src/Model/ElementBase.php @@ -44,19 +44,25 @@ abstract class ElementBase implements ElementInterface, LoggerInterface * (Optional) if specified, the new element will be inserted * before the reference element. */ - public function __construct(string $dom_node_name, ?ElementInterface $parent = null, ?ElementInterface $reference = null) - { + public function __construct( + string $dom_node_name, + protected ?ElementInterface $parent = null, + ?ElementInterface $reference = null, + bool $graft = TRUE, + ) { // If $parent is null, this Element is the root of the DOM document that // stores the media structure. if (isset($parent) && isset($parent->DOMNode)) { $doc = $parent->DOMNode->ownerDocument; $parent_node = $parent->DOMNode; $this->DOMNode = $doc->createElement($dom_node_name); - if ($reference) { - assert($reference instanceof ElementBase); - $parent_node->insertBefore($this->DOMNode, $reference->DOMNode); - } else { - $parent_node->appendChild($this->DOMNode); + if ($graft) { + if ($reference) { + assert($reference instanceof ElementBase); + $parent_node->insertBefore($this->DOMNode, $reference->DOMNode); + } else { + $parent_node->appendChild($this->DOMNode); + } } // Assign this Element as the payload of the DOM node. $this->DOMNode->setMediaProbeElement($this); @@ -83,7 +89,7 @@ public function getParentElement(): ?ElementInterface if ($domNode->getMediaProbeElement() !== $this->getRootElement()) { $parentDomNode = $this->DOMNode->parentNode; assert($parentDomNode instanceof DOMElement); - return $parentDomNode->getMediaProbeElement(); + return $parentDomNode ? $parentDomNode->getMediaProbeElement() : $this->parent; } return null; }