Source for file PelDataWindow.php

Documentation is available at PelDataWindow.php

  1. <?php
  2.  
  3. /*  PEL: PHP Exif Library.  A library with support for reading and
  4.  *  writing all Exif headers in JPEG and TIFF images using PHP.
  5.  *
  6.  *  Copyright (C) 2004, 2005, 2006, 2007  Martin Geisler.
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program in the file COPYING; if not, write to the
  20.  *  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  21.  *  Boston, MA 02110-1301 USA
  22.  */
  23.  
  24. /* $Id$ */
  25.  
  26.  
  27. /**
  28.  * A container for bytes with a limited window of accessible bytes.
  29.  *
  30.  * @author Martin Geisler <mgeisler@users.sourceforge.net>
  31.  * @version $Revision$
  32.  * @date $Date$
  33.  * @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
  34.  * @package PEL
  35.  */
  36.  
  37. /**#@+ Required class definitions. */
  38. require_once('PelException.php');
  39. require_once('PelConvert.php');
  40. /**#@-*/
  41.  
  42.  
  43. /**
  44.  * An exception thrown when an invalid offset is encountered.
  45.  *
  46.  * @package PEL
  47.  * @subpackage Exception
  48.  */
  49.  
  50. /**
  51.  * An exception thrown when an invalid window is encountered.
  52.  *
  53.  * @package PEL
  54.  * @subpackage Exception
  55.  */
  56.  
  57. /**
  58.  * The window.
  59.  *
  60.  * @package PEL
  61.  */
  62. class PelDataWindow {
  63.  
  64.   /**
  65.    * The data held by this window.
  66.    *
  67.    * The string can contain any kind of data, including binary data.
  68.    *
  69.    * @var string 
  70.    */
  71.   private $data '';
  72.  
  73.   /**
  74.    * The byte order currently in use.
  75.    *
  76.    * This will be the byte order used when data is read using the for
  77.    * example the {@link getShort} function.  It must be one of {@link }
  78.    * PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
  79.    *
  80.    * @var PelByteOrder 
  81.    * @see setByteOrder, getByteOrder
  82.    */
  83.   private $order;
  84.  
  85.   /**
  86.    * The start of the current window.
  87.    *
  88.    * All offsets used for access into the data will count from this
  89.    * offset, effectively limiting access to a window starting at this
  90.    * byte.
  91.    *
  92.    * @var int 
  93.    * @see setWindowStart
  94.    */
  95.   private $start  0;
  96.  
  97.   /**
  98.    * The size of the current window.
  99.    *
  100.    * All offsets used for access into the data will be limited by this
  101.    * variable.  A valid offset must be strictly less than this
  102.    * variable.
  103.    *
  104.    * @var int 
  105.    * @see setWindowSize
  106.    */
  107.   private $size   0;
  108.  
  109.  
  110.   /**
  111.    * Construct a new data window with the data supplied.
  112.    *
  113.    * @param mixed the data that this window will contain. This can
  114.    *  either be given as a string (interpreted litteraly as a sequence
  115.    *  of bytes) or a PHP image resource handle. The data will be copied
  116.    *  into the new data window.
  117.    *
  118.    * @param boolean the initial byte order of the window.  This must
  119.    *  be either {@link PelConvert::LITTLE_ENDIAN} or {@link }
  120.    *  PelConvert::BIG_ENDIAN}.  This will be used when integers are
  121.    *  read from the data, and it can be changed later with {@link }
  122.    *  setByteOrder()}.
  123.    */
  124.   function __construct($data ''$endianess PelConvert::LITTLE_ENDIAN{
  125.     if (is_string($data)) {
  126.       $this->data $data;
  127.     elseif (is_resource($data&& get_resource_type($data== 'gd'{
  128.       /* The ImageJpeg() function insists on printing the bytes
  129.        * instead of returning them in a more civil way as a string, so
  130.        * we have to buffer the output... */
  131.       ob_start();
  132.       ImageJpeg($datanullPel::getJPEGQuality());
  133.       $this->data ob_get_clean();
  134.     else {
  135.       throw new PelInvalidArgumentException('Bad type for $data: %s'
  136.                                             gettype($data));
  137.     }
  138.  
  139.     $this->order $endianess;
  140.     $this->size  strlen($this->data);
  141.   }
  142.  
  143.  
  144.   /**
  145.    * Get the size of the data window.
  146.    *
  147.    * @return int the number of bytes covered by the window.  The
  148.    *  allowed offsets go from 0 up to this number minus one.
  149.    *
  150.    * @see getBytes()
  151.    */
  152.   function getSize({
  153.     return $this->size;
  154.   }
  155.  
  156.  
  157.   /**
  158.    * Change the byte order of the data.
  159.    *
  160.    * @param PelByteOrder the new byte order.  This must be either
  161.    *  {@link PelConvert::LITTLE_ENDIAN} or {@link }
  162.    *  PelConvert::BIG_ENDIAN}.
  163.    */
  164.   function setByteOrder($o{
  165.     $this->order $o;
  166.   }
  167.  
  168.  
  169.   /**
  170.    * Get the currently used byte order.
  171.    *
  172.    * @return PelByteOrder this will be either {@link }
  173.    *  PelConvert::LITTLE_ENDIAN} or {@link PelConvert::BIG_ENDIAN}.
  174.    */
  175.   function getByteOrder({
  176.     return $this->order;
  177.   }
  178.  
  179.  
  180.   /* Move the start of the window forward.
  181.    *
  182.    * @param int the new start of the window.  All new offsets will be
  183.    * calculated from this new start offset, and the size of the window
  184.    * will shrink to keep the end of the window in place.
  185.    */
  186.   function setWindowStart($start{
  187.     if ($start || $start $this->size)
  188.       throw new PelDataWindowWindowException('Window [%d, %d] does ' .
  189.                                              'not fit in window [0, %d]',
  190.                                              $start$this->size$this->size);
  191.  
  192.     $this->start += $start;
  193.     $this->size  -= $start;
  194.   }
  195.  
  196.  
  197.   /**
  198.    * Adjust the size of the window.
  199.    *
  200.    * The size can only be made smaller.
  201.    *
  202.    * @param int the desired size of the window.  If the argument is
  203.    *  negative, the window will be shrunk by the argument.
  204.    */
  205.   function setWindowSize($size{
  206.     if ($size 0)
  207.       $size += $this->size;
  208.  
  209.     if ($size || $size $this->size)
  210.       throw new PelDataWindowWindowException('Window [0, %d] ' .
  211.                                              'does not fit in window [0, %d]',
  212.                                              $size$this->size);
  213.     $this->size $size;
  214.   }
  215.   
  216.  
  217.   /**
  218.    * Make a new data window with the same data as the this window.
  219.    *
  220.    * @param mixed if an integer is supplied, then it will be the start
  221.    *  of the window in the clone.  If left unspecified, then the clone
  222.    *  will inherit the start from this object.
  223.    *
  224.    * @param mixed if an integer is supplied, then it will be the size
  225.    *  of the window in the clone.  If left unspecified, then the clone
  226.    *  will inherit the size from this object.
  227.    *
  228.    * @return PelDataWindow a new window that operates on the same data
  229.    *  as this window, but (optionally) with a smaller window size.
  230.    */
  231.   function getClone($start false$size false{
  232.     $c clone $this;
  233.     
  234.     if (is_int($start))
  235.       $c->setWindowStart($start);
  236.  
  237.     if (is_int($size))
  238.       $c->setWindowSize($size);
  239.  
  240.     return $c;
  241.   }
  242.  
  243.  
  244.   /**
  245.    * Validate an offset against the current window.
  246.    *
  247.    * @param int the offset to be validated.  If the offset is negative
  248.    *  or if it is greater than or equal to the current window size,
  249.    *  then a {@link PelDataWindowOffsetException} is thrown.
  250.    *
  251.    * @return void if the offset is valid nothing is returned, if it is
  252.    *  invalid a new {@link PelDataWindowOffsetException} is thrown.
  253.    */
  254.   private function validateOffset($o{
  255.     if ($o || $o >= $this->size)
  256.       throw new PelDataWindowOffsetException('Offset %d not within [%d, %d]',
  257.                                              $o0$this->size-1);
  258.   }
  259.  
  260.  
  261.   /**
  262.    * Return some or all bytes visible in the window.
  263.    *
  264.    * This method works just like the standard {@link substr()}
  265.    * function in PHP with the exception that it works within the
  266.    * window of accessible bytes and does strict range checking.
  267.    * 
  268.    * @param int the offset to the first byte returned.  If a negative
  269.    *  number is given, then the counting will be from the end of the
  270.    *  window.  Invalid offsets will result in a {@link }
  271.    *  PelDataWindowOffsetException} being thrown.
  272.    *
  273.    * @param int the size of the sub-window.  If a negative number is
  274.    *  given, then that many bytes will be omitted from the result.
  275.    *
  276.    * @return string a subset of the bytes in the window.  This will
  277.    *  always return no more than {@link getSize()} bytes.
  278.    */
  279.   function getBytes($start false$size false{
  280.     if (is_int($start)) {
  281.       if ($start 0)
  282.         $start += $this->size;
  283.       
  284.       $this->validateOffset($start);
  285.     else {
  286.       $start 0;
  287.     }
  288.     
  289.     if (is_int($size)) {
  290.       if ($size <= 0)
  291.         $size += $this->size $start;
  292.       
  293.       $this->validateOffset($start+$size);
  294.     else {
  295.       $size $this->size $start;
  296.     }
  297.  
  298.     return substr($this->data$this->start $start$size);
  299.   }
  300.  
  301.  
  302.   /**
  303.    * Return an unsigned byte from the data.
  304.    *
  305.    * @param int the offset into the data.  An offset of zero will
  306.    *  return the first byte in the current allowed window.  The last
  307.    *  valid offset is equal to {@link getSize()}-1.  Invalid offsets
  308.    *  will result in a {@link PelDataWindowOffsetException} being
  309.    *  thrown.
  310.    *
  311.    * @return  int  the unsigned byte found at offset.
  312.    */
  313.   function getByte($o 0{
  314.     /* Validate the offset --- this throws an exception if offset is
  315.      * out of range. */
  316.     $this->validateOffset($o);
  317.  
  318.     /* Translate the offset into an offset into the data. */
  319.     $o += $this->start;
  320.     
  321.     /* Return an unsigned byte. */
  322.     return PelConvert::bytesToByte($this->data$o);
  323.   }
  324.  
  325.  
  326.   /**
  327.    * Return a signed byte from the data.
  328.    *
  329.    * @param int the offset into the data.  An offset of zero will
  330.    *  return the first byte in the current allowed window.  The last
  331.    *  valid offset is equal to {@link getSize()}-1.  Invalid offsets
  332.    *  will result in a {@link PelDataWindowOffsetException} being
  333.    *  thrown.
  334.    *
  335.    * @return  int  the signed byte found at offset.
  336.    */
  337.   function getSByte($o 0{
  338.     /* Validate the offset --- this throws an exception if offset is
  339.      * out of range. */
  340.     $this->validateOffset($o);
  341.  
  342.     /* Translate the offset into an offset into the data. */
  343.     $o += $this->start;
  344.     
  345.     /* Return a signed byte. */
  346.     return PelConvert::bytesToSByte($this->data$o);
  347.   }
  348.  
  349.  
  350.   /**
  351.    * Return an unsigned short read from the data.
  352.    *
  353.    * @param int the offset into the data.  An offset of zero will
  354.    *  return the first short available in the current allowed window.
  355.    *  The last valid offset is equal to {@link getSize()}-2.  Invalid
  356.    *  offsets will result in a {@link PelDataWindowOffsetException}
  357.    *  being thrown.
  358.    *
  359.    * @return  int  the unsigned short found at offset.
  360.    */
  361.   function getShort($o 0{
  362.     /* Validate the offset+1 to see if we can safely get two bytes ---
  363.      * this throws an exception if offset is out of range. */
  364.     $this->validateOffset($o);
  365.     $this->validateOffset($o+1);
  366.  
  367.     /* Translate the offset into an offset into the data. */
  368.     $o += $this->start;
  369.  
  370.     /* Return an unsigned short. */
  371.     return PelConvert::bytesToShort($this->data$o$this->order);
  372.   }
  373.  
  374.  
  375.   /**
  376.    * Return a signed short read from the data.
  377.    *
  378.    * @param int the offset into the data.  An offset of zero will
  379.    *  return the first short available in the current allowed window.
  380.    *  The last valid offset is equal to {@link getSize()}-2.  Invalid
  381.    *  offsets will result in a {@link PelDataWindowOffsetException}
  382.    *  being thrown.
  383.    *
  384.    * @return  int  the signed short found at offset.
  385.    */
  386.   function getSShort($o 0{
  387.     /* Validate the offset+1 to see if we can safely get two bytes ---
  388.      * this throws an exception if offset is out of range. */
  389.     $this->validateOffset($o);
  390.     $this->validateOffset($o+1);
  391.  
  392.     /* Translate the offset into an offset into the data. */
  393.     $o += $this->start;
  394.  
  395.     /* Return a signed short. */
  396.     return PelConvert::bytesToSShort($this->data$o$this->order);
  397.   }
  398.  
  399.  
  400.   /**
  401.    * Return an unsigned long read from the data.
  402.    *
  403.    * @param int the offset into the data.  An offset of zero will
  404.    *  return the first long available in the current allowed window.
  405.    *  The last valid offset is equal to {@link getSize()}-4.  Invalid
  406.    *  offsets will result in a {@link PelDataWindowOffsetException}
  407.    *  being thrown.
  408.    *
  409.    * @return  int  the unsigned long found at offset.
  410.    */
  411.   function getLong($o 0{
  412.     /* Validate the offset+3 to see if we can safely get four bytes
  413.      * --- this throws an exception if offset is out of range. */
  414.     $this->validateOffset($o);
  415.     $this->validateOffset($o+3);
  416.    
  417.     /* Translate the offset into an offset into the data. */
  418.     $o += $this->start;
  419.  
  420.     /* Return an unsigned long. */
  421.     return PelConvert::bytesToLong($this->data$o$this->order);
  422.   }
  423.  
  424.  
  425.   /**
  426.    * Return a signed long read from the data.
  427.    *
  428.    * @param int the offset into the data.  An offset of zero will
  429.    *  return the first long available in the current allowed window.
  430.    *  The last valid offset is equal to {@link getSize()}-4.  Invalid
  431.    *  offsets will result in a {@link PelDataWindowOffsetException}
  432.    *  being thrown.
  433.    *
  434.    * @return  int  the signed long found at offset.
  435.    */
  436.   function getSLong($o 0{
  437.     /* Validate the offset+3 to see if we can safely get four bytes
  438.      * --- this throws an exception if offset is out of range. */
  439.     $this->validateOffset($o);
  440.     $this->validateOffset($o+3);
  441.    
  442.     /* Translate the offset into an offset into the data. */
  443.     $o += $this->start;
  444.  
  445.     /* Return a signed long. */
  446.     return PelConvert::bytesToSLong($this->data$o$this->order);
  447.   }
  448.  
  449.  
  450.   /**
  451.    * Return an unsigned rational read from the data.
  452.    *
  453.    * @param int the offset into the data.  An offset of zero will
  454.    *  return the first rational available in the current allowed
  455.    *  window.  The last valid offset is equal to {@link getSize()}-8.
  456.    *  Invalid offsets will result in a {@link }
  457.    *  PelDataWindowOffsetException} being thrown.
  458.    *
  459.    * @return array the unsigned rational found at offset.  A rational
  460.    *  number is represented as an array of two numbers: the enumerator
  461.    *  and denominator.  Both of these numbers will be unsigned longs.
  462.    */
  463.   function getRational($o 0{
  464.     return array($this->getLong($o)$this->getLong($o+4));
  465.   }
  466.  
  467.  
  468.   /**
  469.    * Return a signed rational read from the data.
  470.    *
  471.    * @param int the offset into the data.  An offset of zero will
  472.    *  return the first rational available in the current allowed
  473.    *  window.  The last valid offset is equal to {@link getSize()}-8.
  474.    *  Invalid offsets will result in a {@link }
  475.    *  PelDataWindowOffsetException} being thrown.
  476.    *
  477.    * @return array the signed rational found at offset.  A rational
  478.    *  number is represented as an array of two numbers: the enumerator
  479.    *  and denominator.  Both of these numbers will be signed longs.
  480.    */
  481.   function getSRational($o 0{
  482.     return array($this->getSLong($o)$this->getSLong($o+4));
  483.   }
  484.  
  485.  
  486.   /**
  487.    * String comparison on substrings.
  488.    *
  489.    * @param int the offset into the data.  An offset of zero will make
  490.    *  the comparison start with the very first byte available in the
  491.    *  window.  The last valid offset is equal to {@link getSize()}
  492.    *  minus the length of the string.  If the string is too long, then
  493.    *  a {@link PelDataWindowOffsetException} will be thrown.
  494.    *
  495.    * @param string the string to compare with.
  496.    *
  497.    * @return boolean true if the string given matches the data in the
  498.    *  window, at the specified offset, false otherwise.  The comparison
  499.    *  will stop as soon as a mismatch if found.
  500.    */
  501.   function strcmp($o$str{
  502.     /* Validate the offset of the final character we might have to
  503.      * check. */
  504.     $s strlen($str);
  505.     $this->validateOffset($o);
  506.     $this->validateOffset($o $s 1);
  507.  
  508.     /* Translate the offset into an offset into the data. */
  509.     $o += $this->start;
  510.   
  511.     /* Check each character, return as soon as the answer is known. */
  512.     for ($i 0$i $s$i++{
  513.       if ($this->data{$o $i!= $str{$i})
  514.         return false;
  515.     }
  516.  
  517.     /* All characters matches each other, return true. */
  518.     return true;
  519.   }
  520.  
  521.  
  522.   /**
  523.    * Return a string representation of the data window.
  524.    *
  525.    * @return string a description of the window with information about
  526.    *  the number of bytes accessible, the total number of bytes, and
  527.    *  the window start and stop.
  528.    */
  529.   function __toString({
  530.     return Pel::fmt('DataWindow: %d bytes in [%d, %d] of %d bytes',
  531.                     $this->size,
  532.                     $this->start$this->start $this->size,
  533.                     strlen($this->data));
  534.   }
  535.  
  536. }
  537.  
  538. ?>

Documentation generated on Thu, 05 May 2011 07:18:59 +0200 by phpDocumentor 1.4.3