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

Documentation generated on Tue, 19 Dec 2006 01:08:17 +0100 by phpDocumentor 1.3.0 SourceForge.net Logo