function ifdToTest($name, $number, PelIfd $ifd) { println(); println('/* Start of IDF %s%d. */', $name, $number); $entries = $ifd->getEntries(); println('$this->assertEqual(count(%s%d->getEntries()), %d);', $name, $number, count($entries)); foreach ($entries as $tag => $entry) { println(); println('$entry = %s%d->getEntry(%d); // %s', $name, $number, $tag, PelTag::getName($ifd->getType(), $tag)); entryToTest('$entry', $entry); } println(); println('/* Sub IFDs of %s%d. */', $name, $number); $sub_ifds = $ifd->getSubIfds(); println('$this->assertEqual(count(%s%d->getSubIfds()), %d);', $name, $number, count($sub_ifds)); $n = 0; $sub_name = $name . $number . '_'; foreach ($sub_ifds as $type => $sub_ifd) { println('%s%d = %s%d->getSubIfd(%d); // IFD %s', $sub_name, $n, $name, $number, $type, $sub_ifd->getName()); println('$this->assertIsA(%s%d, \'PelIfd\');', $sub_name, $n); ifdToTest($sub_name, $n, $sub_ifd); $n++; } println(); if (strlen($ifd->getThumbnailData()) > 0) { println('$thumb_data = file_get_contents(dirname(__FILE__) .'); println(' \'/%s\');', $GLOBALS['thumb_filename']); println('$this->assertEqual(%s%d->getThumbnailData(), $thumb_data);', $name, $number); } else { println('$this->assertEqual(%s%d->getThumbnailData(), \'\');', $name, $number); } println(); println('/* Next IFD. */'); $next = $ifd->getNextIfd(); println('%s%d = %s%d->getNextIfd();', $name, $number + 1, $name, $number); if ($next instanceof PelIfd) { println('$this->assertIsA(%s%d, \'PelIfd\');', $name, $number + 1); println('/* End of IFD %s%d. */', $name, $number); ifdToTest($name, $number + 1, $next); } else { println('$this->assertNull(%s%d);', $name, $number + 1); println('/* End of IFD %s%d. */', $name, $number); } }
/** * Load data into a Image File Directory (IFD). * * @param PelDataWindow the data window that will provide the data. * * @param int the offset within the window where the directory will * be found. */ function load(PelDataWindow $d, $offset) { $thumb_offset = 0; $thumb_length = 0; Pel::debug('Constructing IFD at offset %d from %d bytes...', $offset, $d->getSize()); /* Read the number of entries */ $n = $d->getShort($offset); Pel::debug('Loading %d entries...', $n); $offset += 2; /* Check if we have enough data. */ if ($offset + 12 * $n > $d->getSize()) { $n = floor(($offset - $d->getSize()) / 12); Pel::maybeThrow(new PelIfdException('Adjusted to: %d.', $n)); } for ($i = 0; $i < $n; $i++) { // TODO: increment window start instead of using offsets. $tag = $d->getShort($offset + 12 * $i); Pel::debug('Loading entry with tag 0x%04X: %s (%d of %d)...', $tag, PelTag::getName($this->type, $tag), $i + 1, $n); switch ($tag) { case PelTag::EXIF_IFD_POINTER: case PelTag::GPS_INFO_IFD_POINTER: case PelTag::INTEROPERABILITY_IFD_POINTER: $o = $d->getLong($offset + 12 * $i + 8); Pel::debug('Found sub IFD at offset %d', $o); /* Map tag to IFD type. */ if ($tag == PelTag::EXIF_IFD_POINTER) { $type = PelIfd::EXIF; } elseif ($tag == PelTag::GPS_INFO_IFD_POINTER) { $type = PelIfd::GPS; } elseif ($tag == PelTag::INTEROPERABILITY_IFD_POINTER) { $type = PelIfd::INTEROPERABILITY; } $this->sub[$type] = new PelIfd($type); $this->sub[$type]->load($d, $o); break; case PelTag::JPEG_INTERCHANGE_FORMAT: $thumb_offset = $d->getLong($offset + 12 * $i + 8); $this->safeSetThumbnail($d, $thumb_offset, $thumb_length); break; case PelTag::JPEG_INTERCHANGE_FORMAT_LENGTH: $thumb_length = $d->getLong($offset + 12 * $i + 8); $this->safeSetThumbnail($d, $thumb_offset, $thumb_length); break; default: $format = $d->getShort($offset + 12 * $i + 2); $components = $d->getLong($offset + 12 * $i + 4); /* The data size. If bigger than 4 bytes, the actual data is * not in the entry but somewhere else, with the offset stored * in the entry. */ $s = PelFormat::getSize($format) * $components; if ($s > 0) { $doff = $offset + 12 * $i + 8; if ($s > 4) { $doff = $d->getLong($doff); } $data = $d->getClone($doff, $s); } else { $data = new PelDataWindow(); } try { $entry = $this->newEntryFromData($tag, $format, $components, $data); $this->addEntry($entry); } catch (PelException $e) { /* Throw the exception when running in strict mode, store * otherwise. */ Pel::maybeThrow($e); } /* The format of the thumbnail is stored in this tag. */ // TODO: handle TIFF thumbnail. // if ($tag == PelTag::COMPRESSION) { // $this->thumb_format = $data->getShort(); // } break; } } /* Offset to next IFD */ $o = $d->getLong($offset + 12 * $n); Pel::debug('Current offset is %d, link at %d points to %d.', $offset, $offset + 12 * $n, $o); if ($o > 0) { /* Sanity check: we need 6 bytes */ if ($o > $d->getSize() - 6) { Pel::maybeThrow(new PelIfdException('Bogus offset to next IFD: ' . '%d > %d!', $o, $d->getSize() - 6)); } else { if ($this->type == PelIfd::IFD1) { // IFD1 shouldn't link further... Pel::maybeThrow(new PelIfdException('IFD1 links to another IFD!')); } $this->next = new PelIfd(PelIfd::IFD1); $this->next->load($d, $o); } } else { Pel::debug('Last IFD.'); } }
/** * Turn this entry into a string. * * @return string a string representation of this entry. This is * mostly for debugging. */ function __toString() { $str = Pel::fmt(" Tag: 0x%04X (%s)\n", $this->tag, PelTag::getName($this->ifd_type, $this->tag)); $str .= Pel::fmt(" Format : %d (%s)\n", $this->format, PelFormat::getName($this->format)); $str .= Pel::fmt(" Components: %d\n", $this->components); if ($this->getTag() != PelTag::MAKER_NOTE && $this->getTag() != PelTag::PRINT_IM) { $str .= Pel::fmt(" Value : %s\n", print_r($this->getValue(), true)); } $str .= Pel::fmt(" Text : %s\n", $this->getText()); return $str; }
/** * Construct a new exception indicating a wrong number of * components. * * @param int $type * the type of IFD. * * @param PelTag $tag * the tag for which the violation was found. * * @param int $found * the number of components found. * * @param int $expected * the expected number of components. */ public function __construct($type, $tag, $found, $expected) { parent::__construct('Wrong number of components found for %s tag: %d. ' . 'Expected %d.', PelTag::getName($type, $tag), $found, $expected); $this->tag = $tag; $this->type = $type; }
/** * Construct a new exception indicating an invalid format. * * @param int $type * the type of IFD. * * @param PelTag $tag * the tag for which the violation was found. * * @param PelFormat $found * the format found. * * @param PelFormat $expected * the expected format. */ public function __construct($type, $tag, $found, $expected) { parent::__construct('Unexpected format found for %s tag: PelFormat::%s. ' . 'Expected PelFormat::%s instead.', PelTag::getName($type, $tag), strtoupper(PelFormat::getName($found)), strtoupper(PelFormat::getName($expected))); $this->tag = $tag; $this->type = $type; }