!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/home/jerryg/public_html/gallery2/modules/exif/lib/JPEG/   drwxr-xr-x
Free 318.36 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     JPEG.inc (103.36 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group             |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Author: Sebastian Delmont <sdelmont@zonageek.com>                    |
// | see: http://www.zonageek.com/software/php/jpeg/index.php             |
// | commented and adapted to Gallery 2 by <rehfeld@georg-rehfeld.de>     |
// +----------------------------------------------------------------------+
//
// $Id: JPEG.inc 15342 2006-12-01 21:14:46Z andy_st $

/**************************************************************************
 * JPEG
 * ----
 * A class to read and write JPEG metadata
 *
 * Example Usage:
 *
 * require_once 'Image/JPEG.inc';
 *
 * $jpeg =& new JPEG('images/photos001.jpg');
 *
 * echo $jpeg->getExifField("ApertureValue");
 * echo $jpeg->getIPTCField("Caption");
 *
 * $jpeg->setIPTCField("Byline", "Sebastian Delmont");
 * $jpeg->save("images/photos001-bis.jpg");
 *
 * $info = $jpeg->getBasicInfo();
 * echo $info['Width'] . "x" . $info['Height'];
 *
 *
 **************************************************************************/

//-re- nothing used from PEAR
//require_once 'PEAR.php';

/**
 *
 * @TODO: -re- record error reasons (code + message)
 */
class JPEG // extends PEAR
{
    var 
$_fileName;
    var 
$_fp null;
    var 
$_type 'unknown';

    var 
$_markers;
    var 
$_info;


    
/**
     * Constructs a new JPEG object for the given jpeg file.
     *
     * Constuction is a cheap operation and doesn't require the file to
     * exist. The given filename may actually be a URL instead of a local
     * file.
     *
     * @param string  the name or url of the jpeg file
     */
    
function JPEG($fileName)
    {
        
//$this->PEAR();

        
$this->_fileName $fileName;

        
$this->_fp null;
        
$this->_type 'unknown';

        unset(
$this->_info);
        unset(
$this->_markers);
    }

    
/**
     * Gets the raw EXIF/IPTC information.
     *
     * @return array  An array with all the raw info or false, when parsing failed.
     */
    
function & getRawInfo()
    {
        
$this->_parseAll();

        if (
$this->_markers == null) {
            return 
false;
        }

        return 
$this->_info;
    }

    
/**
     * Gets basic information about the file at hand.
     *
     * @return array  An array with basic info or false, when parsing failed.
     */
    
function & getBasicInfo()
    {
        
$this->_parseAll();

        
$info = array();

        if (
$this->_markers == null) {
            
$false false;
            return 
$false;
        }

        
$info['Name'] = $this->_info['file']['Name'];
        if (isset(
$this->_info['file']['Url'])) {
            
$info['Url'] = $this->_info['file']['Url'];
            
$info['NiceSize'] = "???KB";
        }
        else {
            
$info['Size'] = $this->_info['file']['Size'];
            
$info['NiceSize'] = $this->_info['file']['NiceSize'];
        }

        if (@isset(
$this->_info['sof']['Format'])) {
            
$info['Format'] = $this->_info['sof']['Format'] . " JPEG";
        }
        else {
            
$info['Format'] = $this->_info['sof']['Format'] . " JPEG";
        }

        if (@isset(
$this->_info['sof']['ColorChannels'])) {
            
$info['ColorMode'] = ($this->_info['sof']['ColorChannels'] > 1) ? "Color" "B&W";
        }

        
$info['Width'] = $this->getWidth();
        
$info['Height'] = $this->getHeight();
        
$info['DimStr'] = $this->getDimStr();

        
$dates $this->getDates();

        
$info['DateTime'] = $dates['EarliestTime'];
        
$info['DateTimeStr'] = $dates['EarliestTimeStr'];

        
$info['HasThumbnail'] = $this->hasThumbnail();

        return 
$info;
    }

    
/**
     * Gets an EXIF field from the file. For a list of valid EXIF field names see
     * _exifNameTags().
     *
     * @param string  The name of the EXIF field.
     * @return mixed  The value of the given field, or false, when parsing failed, or the field
     *                does not exist.
     * @see _exifNameTags()
     */
    
function getExifField($field)
    {
        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerExif();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (isset(
$this->_info['exif'][$field])) {
            return 
$this->_info['exif'][$field];
        }

        return 
false;
    }

    
/**
     * Gets an Adobe field from the file. Note, this is NOT XMP data, but file info added by
     * Adobe Photoshop.
     *
     * @param string  The name of the Adobe field.
     * @return mixed  The value of the given field, or false, when parsing failed, or the field
     *                does not exist.
     */
    
function getAdobeField($field)
    {
        if (!isset(
$this->_info['adobe'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (isset(
$this->_info['adobe'][$field])) {
            return 
$this->_info['adobe'][$field];
        }

        return 
false;
    }

    
/**
     * Gets an IPTC field from the file. For a list of valid IPTC field names see
     * _iptcNameTags().
     *
     * @param string  The name of the IPTC field.
     * @return mixed  The value of the given field, or false, when parsing failed, or the field
     *                does not exist.
     * @see _iptcNameTags()
     */
    
function getIPTCField($field)
    {
        if (!isset(
$this->_info['iptc'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (isset(
$this->_info['iptc'][$field])) {
            return 
$this->_info['iptc'][$field];
        }

        return 
false;
    }

    
/**
     * Sets the given value for the given EXIF field. For a list of valid EXIF field names see
     * _exifNameTags().
     *
     * @param string  The name of the EXIF field.
     * @param mixed   The value to set.
     * @return  true, to indicate succes, false otherwise.
     * @see _exifNameTags()
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function setExifField($field$value)
    {
        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerExif();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['exif'] == false) {
            
$this->_info['exif'] = array();
        }

        
$this->_info['exif'][$field] = $value;

        return 
true;
    }

    
/**
     * Sets the given value for the given Adobe field.
     *
     * @param string  The name of the Adobe field.
     * @param mixed   The value to set.
     * @return  true, to indicate succes, false otherwise.
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function setAdobeField($field$value)
    {
        if (!isset(
$this->_info['adobe'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['adobe'] == false) {
            
$this->_info['adobe'] = array();
        }

        
$this->_info['adobe'][$field] = $value;

        return 
true;
    }

    
/**
     * Sets the given value for the given IPTC field. For a list of valid IPTC field names see
     * _iptcNameTags().
     *
     * @param string  The name of the EXIF field.
     * @param mixed   The value to set.
     * @return  true, to indicate succes, false otherwise.
     * @see _iptcNameTags()
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function setIPTCField($field$value)
    {
        if (!isset(
$this->_info['iptc'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['iptc'] == false) {
            
$this->_info['iptc'] = array();
        }

        
$this->_info['iptc'][$field] = $value;

        return 
true;
    }

    
/**
     * Delete the given EXIF field. For a list of valid EXIF field names see
     * _exifNameTags().
     *
     * @param string  The name of the EXIF field.
     * @return  true, to indicate succes, false otherwise.
     * @see _exifNameTags()
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function deleteExifField($field)
    {
        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['exif'] != false) {
            unset(
$this->_info['exif'][$field]);
        }

        return 
true;
    }

    
/**
     * Delete the given Adobe field.
     *
     * @param string  The name of the Adobe field.
     * @return  true, to indicate succes, false otherwise.
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function deleteAdobeField($field)
    {
        if (!isset(
$this->_info['adobe'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['adobe'] != false) {
            unset(
$this->_info['adobe'][$field]);
        }

        return 
true;
    }

    
/**
     * Delete the given IPTC field. For a list of valid IPTC field names see
     * _iptcNameTags().
     *
     * @param string  The name of the IPTC field.
     * @return  true, to indicate succes, false otherwise.
     * @see _iptcNameTags()
     * @see save()
     * @TODO: -re- check for valid name?
     */
    
function deleteIPTCField($field)
    {
        if (!isset(
$this->_info['iptc'])) {
            
$this->_parseMarkerAdobe();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (
$this->_info['iptc'] != false) {
            unset(
$this->_info['iptc'][$field]);
        }

        return 
true;
    }

    
/**
     * Get datetime collected from several EXIF fields.
     *
     * @return array  An array with datetime info.
     */
    
function getDates()
    {
        
$this->_parseAll();

        if (
$this->_markers == null) {
            return 
false;
        }

        
$dates = array();

        
$latestTime 0;
        
$latestTimeSource "";
        
$earliestTime time();
        
$earliestTimeSource "";

        if (@isset(
$this->_info['exif']['DateTime'])) {
            
$dates['ExifDateTime'] = $this->_info['exif']['DateTime'];

            
$aux $this->_info['exif']['DateTime'];
            
$aux{4} = "-";
            
$aux{7} = "-";
            
$t strtotime($aux);

            if (
$t $latestTime) {
                
$latestTime $t;
                
$latestTimeSource "ExifDateTime";
            }

            if (
$t $earliestTime) {
                
$earliestTime $t;
                
$earliestTimeSource "ExifDateTime";
            }
        }

        if (@isset(
$this->_info['exif']['DateTimeOriginal'])) {
            
$dates['ExifDateTimeOriginal'] = $this->_info['exif']['DateTime'];

            
$aux $this->_info['exif']['DateTimeOriginal'];
            
$aux{4} = "-";
            
$aux{7} = "-";
            
$t strtotime($aux);

            if (
$t $latestTime) {
                
$latestTime $t;
                
$latestTimeSource "ExifDateTimeOriginal";
            }

            if (
$t $earliestTime) {
                
$earliestTime $t;
                
$earliestTimeSource "ExifDateTimeOriginal";
            }
        }

        if (@isset(
$this->_info['exif']['DateTimeDigitized'])) {
            
$dates['ExifDateTimeDigitized'] = $this->_info['exif']['DateTime'];

            
$aux $this->_info['exif']['DateTimeDigitized'];
            
$aux{4} = "-";
            
$aux{7} = "-";
            
$t strtotime($aux);

            if (
$t $latestTime) {
                
$latestTime $t;
                
$latestTimeSource "ExifDateTimeDigitized";
            }

            if (
$t $earliestTime) {
                
$earliestTime $t;
                
$earliestTimeSource "ExifDateTimeDigitized";
            }
        }

        if (@isset(
$this->_info['iptc']['DateCreated'])) {
            
$dates['IPTCDateCreated'] = $this->_info['iptc']['DateCreated'];

            
$aux $this->_info['iptc']['DateCreated'];
            
$aux substr($aux04) . "-" substr($aux42) . "-" substr($aux62);
            
$t strtotime($aux);

            if (
$t $latestTime) {
                
$latestTime $t;
                
$latestTimeSource "IPTCDateCreated";
            }

            if (
$t $earliestTime) {
                
$earliestTime $t;
                
$earliestTimeSource "IPTCDateCreated";
            }
        }

        if (@isset(
$this->_info['file']['UnixTime'])) {
            
$dates['FileModified'] = $this->_info['file']['UnixTime'];

            
$t $this->_info['file']['UnixTime'];

            if (
$t $latestTime) {
                
$latestTime $t;
                
$latestTimeSource "FileModified";
            }

            if (
$t $earliestTime) {
                
$earliestTime $t;
                
$earliestTimeSource "FileModified";
            }
        }

        
$dates['Time'] = $earliestTime;
        
$dates['TimeSource'] = $earliestTimeSource;
        
$dates['TimeStr'] = date("Y-m-d H:i:s"$earliestTime);
        
$dates['EarliestTime'] = $earliestTime;
        
$dates['EarliestTimeSource'] = $earliestTimeSource;
        
$dates['EarliestTimeStr'] = date("Y-m-d H:i:s"$earliestTime);
        
$dates['LatestTime'] = $latestTime;
        
$dates['LatestTimeSource'] = $latestTimeSource;
        
$dates['LatestTimeStr'] = date("Y-m-d H:i:s"$latestTime);

        return 
$dates;
    }

    
/**
     * Gets the pixel width of the image.
     *
     * @return mixed  The integer pixel width, when it could be determined, false otherwise.
     */
    
function getWidth()
    {
        if (!isset(
$this->_info['sof'])) {
            
$this->_parseMarkerSOF();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (isset(
$this->_info['sof']['ImageWidth'])) {
            return 
$this->_info['sof']['ImageWidth'];
        }

        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerExif();
        }

        if (isset(
$this->_info['exif']['PixelXDimension'])) {
            return 
$this->_info['exif']['PixelXDimension'];
        }

        return 
false;
    }

    
/**
     * Gets the pixel height of the image.
     *
     * @return mixed  The integer pixel height, when it could be determined, false otherwise.
     */
    
function getHeight()
    {
        if (!isset(
$this->_info['sof'])) {
            
$this->_parseMarkerSOF();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (isset(
$this->_info['sof']['ImageHeight'])) {
            return 
$this->_info['sof']['ImageHeight'];
        }

        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerExif();
        }

        if (isset(
$this->_info['exif']['PixelYDimension'])) {
            return 
$this->_info['exif']['PixelYDimension'];
        }

        return 
false;
    }

    
/**
     * Gets width and height of the image as a string.
     *
     * @return mixed  A string with the dimensions, false, when parsing failed.
     */
    
function getDimStr()
    {
        if (
$this->_markers == null) {
            return 
false;
        }

        
$w $this->getWidth();
        
$h $this->getHeight();

        return 
"WIDTH='" $w "' HEIGHT='" $h "'";
    }

    
/**
     * Checks for existence of a thumbnail image in the JPEG. Thumbnails may be in the EXIF data
     * or the Adobe specific data or both.
     *
     * @param string  Flag indicating in which section should be looked for the thumbnail, one
     *                of 'any', 'exif' or 'adobe'.
     * @return mixed  String indicating, where the thumbnail was found, 'exif' or 'adobe'.
     *                False, if there is no thumbnail or parsing failed.
     * @TODO: -re- 'any' should check in adobe too!
     * @TODO: -re- when found in adobe, 'adobe' should be returned!
     * @TODO: -re- define integer constants instead of using strings!
     */
    
function hasThumbnail($which 'any')
    {
        if ((
$which == 'any') || ($which == 'exif')) {
            if (!isset(
$this->_info['exif'])) {
                
$this->_parseMarkerExif();
            }

            if (
$this->_markers == null) {
                return 
false;
            }

            if (isset(
$this->_info['exif']) && is_array($this->_info['exif'])) {
                if (isset(
$this->_info['exif']['JFIFThumbnail'])) {
                    return 
'exif';
                }
            }
        }

        if (
$which == 'adobe') {
            if (!isset(
$this->_info['adobe'])) {
                
$this->_parseMarkerAdobe();
            }

            if (
$this->_markers == null) {
                return 
false;
            }

            if (isset(
$this->_info['adobe']) && is_array($this->_info['adobe'])) {
                if (isset(
$this->_info['adobe']['ThumbnailData'])) {
                    return 
'exif';
                }
            }
        }

        return 
false;
    }

    
/**
     * Sends the thumbnail to stdout/browser. The thumbnail image data is prefixed by a
     * "Content-type: image/jpeg" header.
     *
     * @param string  Flag indicating in which section should be looked for the thumbnail, one
     *                of 'any', 'exif' or 'adobe'.
     * @return boolean  True, if thumbnail data was spit out,false, if there is no thumbnail
     *                  or parsing failed.
     * @TODO: -re- define integer constants instead of using strings!
     */
    
function sendThumbnail($which 'any')
    {
        
$data null;

        if ((
$which == 'any') || ($which == 'exif')) {
            if (!isset(
$this->_info['exif'])) {
                
$this->_parseMarkerExif();
            }

            if (
$this->_markers == null) {
                return 
false;
            }

            if (isset(
$this->_info['exif']) && is_array($this->_info['exif'])) {
                if (isset(
$this->_info['exif']['JFIFThumbnail'])) {
                    
$data =& $this->_info['exif']['JFIFThumbnail'];
                }
            }
        }

        if ((
$which == 'adobe') || ($data == null)){
            if (!isset(
$this->_info['adobe'])) {
                
$this->_parseMarkerAdobe();
            }

            if (
$this->_markers == null) {
                return 
false;
            }

            if (isset(
$this->_info['adobe']) && is_array($this->_info['adobe'])) {
                if (isset(
$this->_info['adobe']['ThumbnailData'])) {
                    
$data =& $this->_info['adobe']['ThumbnailData'];
                }
            }
        }

        if (
$data != null) {
            
header("Content-type: image/jpeg");
            echo 
$data;
            return 
true;
        }

        return 
false;
    }

    
/**
     * Saves the potentially changed JPEG to the given file name path. If no filename is given,
     * the current filename is used and thus the original file is overwritten.
     *
     * @param string  The filename to write the JPEG to. This may not be an URL.
     * @TODO: -re- indicate success/failure on return
     */
    
function save($fileName "") {
      if (
$fileName == "") {
        
$tmpName $this->_fileName ".tmp";
        if (
$this->_writeJPEG($tmpName) && file_exists($tmpName)) {
          
rename($tmpName$this->_fileName);
        }
      }
      else {
        
$this->_writeJPEG($fileName);
      }
    }

    
/*************************************************************/
    /* PRIVATE FUNCTIONS (Internal Use Only!)                    */
    /*************************************************************/

    /**
     * Disposes all allocated resources.
     *
     * @access private
     * @TODO: -re- hmm, requiered by PEAR?
     */
    
function _dispose()
    {
        
$this->_fileName null;

        
$this->_fp null;
        
$this->_type 'unknown';

        unset(
$this->_markers);
        unset(
$this->_info);
    }

    
/**
     * Reads the associated jpeg file and preparses important meta data into
     * internal array slots.
     *
     * The jpeg file isn't parsed completely though, only the meta data
     * parts are copied over binary into the _markers array. The primary image data
     * is skipped over.
     *
     * @return  true, when the file could be read and preparsed correctly,
     *          false, when any error occurrs
     * @see JPEG::_parseAll
     * @see JPEG::_markers
     * @access private
     */
    
function _readJPEG()
    {
        unset(
$this->_markers);
        unset(
$this->_info);
        
$this->_markers = array();
        
$this->_info = array();

        
$this->_fp = @fopen($this->_fileName'rb');
        if (
$this->_fp) {
            if (
file_exists($this->_fileName)) {
                
$this->_type 'file';
            }
            else {
                
$this->_type 'url';
            }
        }
        else {
            
$this->_fp null;
            return 
false;  // ERROR: Can't open file
        
}

        
// Check for the JPEG signature
        
$c1 ord(fgetc($this->_fp));
        
$c2 ord(fgetc($this->_fp));

        if (
$c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
            
$this->_markers null;
            return 
false;  // ERROR: File is not a JPEG
        
}

        
$count 0;

        
$done false;
        
$ok true;

        while (!
$done) {
            
$capture false;

          
// First, skip any non 0xFF bytes
            
$discarded 0;
            
$c ord(fgetc($this->_fp));
            while (!
feof($this->_fp) && ($c != 0xFF)) {
                
$discarded++;
                
$c ord(fgetc($this->_fp));
            }
          
// Then skip all 0xFF until the marker byte
            
do {
                
$marker ord(fgetc($this->_fp));
            } while (!
feof($this->_fp) && ($marker == 0xFF));

            if (
feof($this->_fp)) {
                return 
false// ERROR: Unexpected EOF
            
}
            if (
$discarded != 0) {
                return 
false// ERROR: Extraneous data
            
}

            
$length ord(fgetc($this->_fp)) * 256 ord(fgetc($this->_fp));
            if (
feof($this->_fp)) {
                return 
false// ERROR: Unexpected EOF
            
}
            if (
$length 2) {
                return 
false// ERROR: Extraneous data
            
}
            
$length $length 2// The length we got counts itself

            
switch ($marker) {
            case 
0xC0:    // SOF0
            
case 0xC1:    // SOF1
            
case 0xC2:    // SOF2
            
case 0xC9:    // SOF9
            
case 0xE0:    // APP0: JFIF data
            
case 0xE1:    // APP1: EXIF data
            
case 0xED:    // APP13: IPTC / Photoshop data
                
$capture true;
                break;
            case 
0xDA:    // SOS: Start of scan... the image itself and the last block on the file
                
$capture false;
                
$length = -1;  // This field has no length... it includes all data until EOF
                
$done true;
                break;
            default:
                
$capture true;//false;
                
break;
            }

            
$this->_markers[$count] = array();
            
$this->_markers[$count]['marker'] = $marker;
            
$this->_markers[$count]['length'] = $length;

            if (
$capture) {
                if (
$length 0) {
            
$this->_markers[$count]['data'] = fread($this->_fp$length);
        } else {
            
$this->_markers[$count]['data'] = '';
        }
            }
            elseif (!
$done) {
                
$result = @fseek($this->_fp$lengthSEEK_CUR);
              
// fseek doesn't seem to like HTTP 'files', but fgetc has no problem
                
if (!($result === 0)) {
                    for (
$i 0$i $length$i++) {
                        
fgetc($this->_fp);
                    }
                }
            }
            
$count++;
        }

        if (
$this->_fp) {
            
fclose($this->_fp);
            
$this->_fp null;
        }

        return 
$ok;
    }

    
/**
     * Parses all meta data from the JPEG file.
     *
     * @return boolean  A flag indicating success.
     */
    
function _parseAll()
    {
        if (!isset(
$this->_markers)) {
            
$this->_readJPEG();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        if (!isset(
$this->_info['jfif'])) {
            
$this->_parseMarkerJFIF();
        }
        if (!isset(
$this->_info['jpeg'])) {
            
$this->_parseMarkerSOF();
        }
        if (!isset(
$this->_info['exif'])) {
            
$this->_parseMarkerExif();
        }
        if (!isset(
$this->_info['adobe'])) {
            
$this->_parseMarkerAdobe();
        }
        if (!isset(
$this->_info['file'])) {
            
$this->_parseFileInfo();
        }
        return 
true;
    }

    
/**
     * @TODO: -re- comment
     */
    
function _writeJPEG($outputName)
    {
        
$this->_parseAll();

        
$wroteEXIF false;
        
$wroteAdobe false;

        
$this->_fp = @fopen($this->_fileName'r');
        if (
$this->_fp) {
            if (
file_exists($this->_fileName)) {
                
$this->_type 'file';
            }
            else {
                
$this->_type 'url';
            }
        }
        else {
            
$this->_fp null;
            return 
false;  // ERROR: Can't open file
        
}

        
$this->_fpout fopen($outputName'wb');
        if (
$this->_fpout) {
        }
        else {
            
$this->_fpout null;
            
fclose($this->_fp);
            
$this->_fp null;
            return 
false;  // ERROR: Can't open output file
        
}

        
// Check for the JPEG signature
        
$c1 ord(fgetc($this->_fp));
        
$c2 ord(fgetc($this->_fp));

        if (
$c1 != 0xFF || $c2 != 0xD8) {   // (0xFF + SOI)
            
return false;  // ERROR: File is not a JPEG
        
}

        
fputs($this->_fpoutchr(0xFF), 1);
        
fputs($this->_fpoutchr(0xD8), 1); // (0xFF + SOI)

        
$count 0;

        
$done false;
        
$ok true;

        while (!
$done) {
          
// First, skip any non 0xFF bytes
            
$discarded 0;
            
$c ord(fgetc($this->_fp));
            while (!
feof($this->_fp) && ($c != 0xFF)) {
                
$discarded++;
                
$c ord(fgetc($this->_fp));
            }
          
// Then skip all 0xFF until the marker byte
            
do {
                
$marker ord(fgetc($this->_fp));
            } while (!
feof($this->_fp) && ($marker == 0xFF));

            if (
feof($this->_fp)) {
                
$ok false;
                break; 
// ERROR: Unexpected EOF
            
}
            if (
$discarded != 0) {
                
$ok false;
                break; 
// ERROR: Extraneous data
            
}

            
$length ord(fgetc($this->_fp)) * 256 ord(fgetc($this->_fp));
            if (
feof($this->_fp)) {
                
$ok false;
                break; 
// ERROR: Unexpected EOF
            
}
            if (
$length 2) {
                
$ok false;
                break; 
// ERROR: Extraneous data
            
}
            
$length $length 2// The length we got counts itself

            
unset($data);
            if (
$marker == 0xE1) { // APP1: EXIF data
                
$data =& $this->_createMarkerEXIF();
                
$wroteEXIF true;
            }
            elseif (
$marker == 0xED) { // APP13: IPTC / Photoshop data
                
$data =& $this->_createMarkerAdobe();
                
$wroteAdobe true;
            }
            elseif (
$marker == 0xDA) { // SOS: Start of scan... the image itself and the last block on the file
                
$done true;
            }

            if (!
$wroteEXIF && (($marker 0xE0) || ($marker 0xEF))) {
                if (isset(
$this->_info['exif']) && is_array($this->_info['exif'])) {
                    
$exif =& $this->_createMarkerEXIF();
                    
$this->_writeJPEGMarker(0xE1strlen($exif), $exif0);
                    unset(
$exif);
                }
                
$wroteEXIF true;
            }

            if (!
$wroteAdobe && (($marker 0xE0) || ($marker 0xEF))) {
                if ((isset(
$this->_info['adobe']) && is_array($this->_info['adobe']))
                || (isset(
$this->_info['iptc']) && is_array($this->_info['iptc']))) {
                    
$adobe =& $this->_createMarkerAdobe();
                    
$this->_writeJPEGMarker(0xEDstrlen($adobe), $adobe0);
                    unset(
$adobe);
                }
                
$wroteAdobe true;
            }

            
$origLength $length;
            if (isset(
$data)) {
                
$length strlen($data);
            }

            if (
$marker != -1) {
                
$this->_writeJPEGMarker($marker$length$data$origLength);
            }
        }

        if (
$this->_fp) {
            
fclose($this->_fp);
            
$this->_fp null;
        }

        if (
$this->_fpout) {
            
fclose($this->_fpout);
            
$this->_fpout null;
        }

        return 
$ok;
    }

    
/**
     * @TODO: -re- comment
     */
    
function _writeJPEGMarker($marker$length, &$data$origLength)
    {
        if (
$length <= 0) {
            return 
false;
        }

        
fputs($this->_fpoutchr(0xFF), 1);
        
fputs($this->_fpoutchr($marker), 1);
        
fputs($this->_fpoutchr((($length 2) & 0x0000FF00) >> 8), 1);
        
fputs($this->_fpoutchr((($length 2) & 0x000000FF) >> 0), 1);

        if (isset(
$data)) {
            
// Copy the generated data
            
fputs($this->_fpout$data$length);

            if (
$origLength 0) {   // Skip the original data
                
$result = @fseek($this->_fp$origLengthSEEK_CUR);
                
// fseek doesn't seem to like HTTP 'files', but fgetc has no problem
                
if ($result != 0) {
                    for (
$i 0$i $origLength$i++) {
                        
fgetc($this->_fp);
                    }
                }
            }
        }
        else {
            if (
$marker == 0xDA) {  // Copy until EOF
                
while (!feof($this->_fp)) {
                    
$data =& fread($this->_fp1024 16);
                    
fputs($this->_fpout$datastrlen($data));
                }
            }
            else { 
// Copy only $length bytes
                
$data =& fread($this->_fp$length);
                
fputs($this->_fpout$data$length);
            }
        }

        return 
true;
    }

    
/**
     * Puts basic file information into the internal array _info['file'].
     * Keys are 'Name', 'Size', 'NiceSize', 'UnixTime' and 'Url'. If the file is remote (an url)
     * then only 'Name' and 'Url' are set, local files have no 'Url' key.
     *
     * @return boolean  True
     * @access private
     * @TODO: -re- have a valid 'Url' even for local files?
     */
    
function _parseFileInfo()
    {
        if (
file_exists($this->_fileName)) {
            
$this->_info['file'] = array();
            
$this->_info['file']['Name'] = basename($this->_fileName);
            
$this->_info['file']['Size'] = filesize($this->_fileName);
            if (
$this->_info['file']['Size'] < 1024) {
                
$this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
            }
            elseif (
$this->_info['file']['Size'] < (1024 1024)) {
                
$this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'KB';
            }
            elseif (
$this->_info['file']['Size'] < (1024 1024 1024)) {
                
$this->_info['file']['NiceSize'] = round($this->_info['file']['Size'] / 1024) . 'MB';
            }
            else {
                
$this->_info['file']['NiceSize'] = $this->_info['file']['Size'] . 'B';
            }
            
$this->_info['file']['UnixTime'] = filemtime($this->_fileName);
        }
        else {
            
$this->_info['file'] = array();
            
$this->_info['file']['Name'] = basename($this->_fileName);
            
$this->_info['file']['Url'] = $this->_fileName;
        }

        return 
true;
    }

    
/*************************************************************/
    
function _parseMarkerJFIF()
    {
        if (!isset(
$this->_markers)) {
            
$this->_readJPEG();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        
$data null;
        
$count count($this->_markers);
        for (
$i 0$i $count$i++) {
            if (
$this->_markers[$i]['marker'] == 0xE0) {
                
$signature $this->_getFixedString($this->_markers[$i]['data'], 04);
                if (
$signature == 'JFIF') {
                    
$data =& $this->_markers[$i]['data'];
                    break;
                }
            }
        }

        if (
$data == null) {
            
$this->_info['jfif'] = false;
            return 
false;
        }

        
$pos 0;
        
$this->_info['jfif'] = array();


        
$vmaj $this->_getByte($data5);
        
$vmin $this->_getByte($data6);

        
$this->_info['jfif']['Version'] = sprintf('%d.%02d'$vmaj$vmin);

        
$units $this->_getByte($data7);
        switch (
$units) {
        case 
0:
            
$this->_info['jfif']['Units'] = 'pixels';
            break;
        case 
1:
            
$this->_info['jfif']['Units'] = 'dpi';
            break;
        case 
2:
            
$this->_info['jfif']['Units'] = 'dpcm';
            break;
        default:
            
$this->_info['jfif']['Units'] = 'unknown';
            break;
        }

        
$xdens $this->_getShort($data8);
        
$ydens $this->_getShort($data10);

        
$this->_info['jfif']['XDensity'] = $xdens;
        
$this->_info['jfif']['YDensity'] = $ydens;

        
$thumbx $this->_getByte($data12);
        
$thumby $this->_getByte($data13);

        
$this->_info['jfif']['ThumbnailWidth'] = $thumbx;
        
$this->_info['jfif']['ThumbnailHeight'] = $thumby;

        return 
true;
    }

    
/**
     * Parses SOF (Start Of Frame) JPEG/EXIF info.
     *
     * @return boolean  true, when parsing succeded and SOF data was found, false otherwise.
     */
    
function _parseMarkerSOF()
    {
        if (!isset(
$this->_markers)) {
            
$this->_readJPEG();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        
$data null;
        
$count count($this->_markers);
        for (
$i 0$i $count$i++) {
            switch (
$this->_markers[$i]['marker']) {
            case 
0xC0// SOF0
            
case 0xC1// SOF1
            
case 0xC2// SOF2
            
case 0xC9// SOF9
                
$data =& $this->_markers[$i]['data'];
                
$marker $this->_markers[$i]['marker'];
                break;
            }
        }

        if (
$data == null) {
            
$this->_info['sof'] = false;
            return 
false;
        }

        
$pos 0;
        
$this->_info['sof'] = array();


        switch (
$marker) {
        case 
0xC0// SOF0
            
$format 'Baseline';
            break;
        case 
0xC1// SOF1
            
$format 'Progessive';
            break;
        case 
0xC2// SOF2
            
$format 'Non-baseline';
            break;
        case 
0xC9// SOF9
            
$format 'Arithmetic';
            break;
        default:
            return 
false;
        }


        
$this->_info['sof']['Format'] = $format;

        
$this->_info['sof']['SamplePrecision'] = $this->_getByte($data$pos 0);
        
$this->_info['sof']['ImageHeight'] = $this->_getShort($data$pos 1);
        
$this->_info['sof']['ImageWidth'] = $this->_getShort($data$pos 3);
        
$this->_info['sof']['ColorChannels'] = $this->_getByte($data$pos 5);

        return 
true;
    }

    
/*************************************************************/
    
function _parseMarkerExif()
    {
        if (!isset(
$this->_markers)) {
            
$this->_readJPEG();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        
$data null;
        
$count count($this->_markers);
        for (
$i 0$i $count$i++) {
            if (
$this->_markers[$i]['marker'] == 0xE1) {
                
$signature $this->_getFixedString($this->_markers[$i]['data'], 06);
                if (
$signature == "Exif\0\0") {
                    
$data =& $this->_markers[$i]['data'];
                    break;
                }
            }
        }

        if (
$data == null) {
            
$this->_info['exif'] = false;
            return 
false;
        }
        
$pos 6;
        
$this->_info['exif'] = array();

        
// We don't increment $pos after this because Exif uses offsets relative to this point

        
$byteAlign $this->_getShort($data$pos 0);

        if (
$byteAlign == 0x4949) { // "II"
            
$isBigEndian false;
        }
        elseif (
$byteAlign == 0x4D4D) { // "MM"
            
$isBigEndian true;
        }
        else {
            return 
false// Unexpected data
        
}

        
$alignCheck $this->_getShort($data$pos 2$isBigEndian);
        if (
$alignCheck != 0x002A// That's the expected value
            
return false// Unexpected data

        
if ($isBigEndian) {
            
$this->_info['exif']['ByteAlign'] = "Big Endian";
        }
        else {
            
$this->_info['exif']['ByteAlign'] = "Little Endian";
        }

        
$offsetIFD0 $this->_getLong($data$pos 4$isBigEndian);
        if (
$offsetIFD0 8)
            return 
false// Unexpected data

        
$offsetIFD1 $this->_readIFD($data$pos$offsetIFD0$isBigEndian'ifd0');
        if (
$offsetIFD1 != 0)
            
$this->_readIFD($data$pos$offsetIFD1$isBigEndian'ifd1');

        return 
true;
    }

    
/*************************************************************/
    
function _readIFD(&$data$base$offset$isBigEndian$mode)
    {
        
$EXIFTags $this->_exifTagNames($mode);

        
$numEntries $this->_getShort($data$base $offset$isBigEndian);
        
$offset += 2;

        
$exifTIFFOffset 0;
        
$exifTIFFLength 0;
        
$exifThumbnailOffset 0;
        
$exifThumbnailLength 0;

        for (
$i 0$i $numEntries$i++) {
            
$tag $this->_getShort($data$base $offset$isBigEndian);
            
$offset += 2;
            
$type $this->_getShort($data$base $offset$isBigEndian);
            
$offset += 2;
            
$count $this->_getLong($data$base $offset$isBigEndian);
            
$offset += 4;

            if ((
$type 1) || ($type 12))
                return 
false// Unexpected Type

            
$typeLengths = array( -111248112484);

            
$dataLength $typeLengths[$type] * $count;
            if (
$dataLength 4) {
                
$dataOffset $this->_getLong($data$base $offset$isBigEndian);
                
$rawValue $this->_getFixedString($data$base $dataOffset$dataLength);
            }
            else {
                
$rawValue $this->_getFixedString($data$base $offset$dataLength);
            }
            
$offset += 4;

            switch (
$type) {
            case 
1:    // UBYTE
                
if ($count == 1) {
                    
$value $this->_getByte($rawValue0);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getByte($rawValue$j);
                }
                break;
            case 
2:    // ASCII
                
$value $rawValue;
                break;
            case 
3:    // USHORT
                
if ($count == 1) {
                    
$value $this->_getShort($rawValue0$isBigEndian);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getShort($rawValue$j 2$isBigEndian);
                }
                break;
            case 
4:    // ULONG
                
if ($count == 1) {
                    
$value $this->_getLong($rawValue0$isBigEndian);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getLong($rawValue$j 4$isBigEndian);
                }
                break;
            case 
5:    // URATIONAL
                
if ($count == 1) {
                    
$a $this->_getLong($rawValue0$isBigEndian);
                    
$b $this->_getLong($rawValue4$isBigEndian);
                    
$value = array();
                    
$value['val'] = 0;
                    
$value['num'] = $a;
                    
$value['den'] = $b;
                    if ((
$a != 0) && ($b != 0)) {
                        
$value['val'] = $a $b;
                    }
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++) {
                        
$a $this->_getLong($rawValue$j 8$isBigEndian);
                        
$b $this->_getLong($rawValue, ($j 8) + 4$isBigEndian);
                        
$value = array();
                        
$value[$j]['val'] = 0;
                        
$value[$j]['num'] = $a;
                        
$value[$j]['den'] = $b;
                        if ((
$a != 0) && ($b != 0))
                            
$value[$j]['val'] = $a $b;
                    }
                }
                break;
            case 
6:    // SBYTE
                
if ($count == 1) {
                    
$value $this->_getByte($rawValue0);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getByte($rawValue$j);
                }
                break;
            case 
7:    // UNDEFINED
                
$value $rawValue;
                break;
            case 
8:    // SSHORT
                
if ($count == 1) {
                    
$value $this->_getShort($rawValue0$isBigEndian);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getShort($rawValue$j 2$isBigEndian);
                }
                break;
            case 
9:    // SLONG
                
if ($count == 1) {
                    
$value $this->_getLong($rawValue0$isBigEndian);
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++)
                        
$value[$j] = $this->_getLong($rawValue$j 4$isBigEndian);
                }
                break;
            case 
10:   // SRATIONAL
                
if ($count == 1) {
                    
$a $this->_getLong($rawValue0$isBigEndian);
                    
$b $this->_getLong($rawValue4$isBigEndian);
                    
$value = array();
                    
$value['val'] = 0;
                    
$value['num'] = $a;
                    
$value['den'] = $b;
                    if ((
$a != 0) && ($b != 0))
                        
$value['val'] = $a $b;
                }
                else {
                    
$value = array();
                    for (
$j 0$j $count$j++) {
                        
$a $this->_getLong($rawValue$j 8$isBigEndian);
                        
$b $this->_getLong($rawValue, ($j 8) + 4$isBigEndian);
                        
$value = array();
                        
$value[$j]['val'] = 0;
                        
$value[$j]['num'] = $a;
                        
$value[$j]['den'] = $b;
                        if ((
$a != 0) && ($b != 0))
                            
$value[$j]['val'] = $a $b;
                    }
                }
                break;
            case 
11:   // FLOAT
                
$value $rawValue;
                break;

            case 
12:   // DFLOAT
                
$value $rawValue;
                break;
            default:
                return 
false// Unexpected Type
            
}

            
$tagName '';
            if ((
$mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
                
$this->_readIFD($data$base$value$isBigEndian'exif');
            }
            elseif ((
$mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
                
$this->_readIFD($data$base$value$isBigEndian'gps');
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
                
$exifTIFFOffset $value;
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
                
$exifTIFFLength $value;
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
                
$exifThumbnailOffset $value;
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
                
$exifThumbnailLength $value;
            }
            elseif ((
$mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
                
$this->_readIFD($data$base$value$isBigEndian'interop');
            }
            
// elseif (($mode == 'exif') && ($tag == 0x927C)) {  // MakerNote
            // }
            
else {
                if (isset(
$EXIFTags[$tag])) {
                    
$tagName $EXIFTags[$tag];
                    if (isset(
$this->_info['exif'][$tagName])) {
                        if (!
is_array($this->_info['exif'][$tagName])) {
                            
$aux = array();
                            
$aux[0] = $this->_info['exif'][$tagName];
                            
$this->_info['exif'][$tagName] = $aux;
                        }

                        
$this->_info['exif'][$tagName][count($this->_info['exif'][$tagName])] = $value;
                    }
                    else {
                        
$this->_info['exif'][$tagName] = $value;
                    }
                }
                else {
#echo sprintf("<h1>Unknown tag %02x (t: %d l: %d) %s in %s</h1>", $tag, $type, $count, $mode, $this->_fileName);
                    // Unknown Tags will be ignored!!!
                    // That's because the tag might be a pointer (like the Exif tag)
                    // and saving it without saving the data it points to might
                    // create an invalid file.
                
}
            }
        }

        if ((
$exifThumbnailOffset 0) && ($exifThumbnailLength 0)) {
            
$this->_info['exif']['JFIFThumbnail'] = $this->_getFixedString($data$base $exifThumbnailOffset$exifThumbnailLength);
        }

        if ((
$exifTIFFOffset 0) && ($exifTIFFLength 0)) {
            
$this->_info['exif']['TIFFStrips'] = $this->_getFixedString($data$base $exifTIFFOffset$exifTIFFLength);
        }

        
$nextOffset $this->_getLong($data$base $offset$isBigEndian);
        return 
$nextOffset;
    }

    
/*************************************************************/
    
function & _createMarkerExif()
    {
        
$data null;
        
$count count($this->_markers);
        for (
$i 0$i $count$i++) {
            if (
$this->_markers[$i]['marker'] == 0xE1) {
                
$signature $this->_getFixedString($this->_markers[$i]['data'], 06);
                if (
$signature == "Exif\0\0") {
                    
$data =& $this->_markers[$i]['data'];
                    break;
                }
            }
        }

        if (!isset(
$this->_info['exif'])) {
            
$false false;
            return 
$false;
        }

        
$data "Exif\0\0";
        
$pos 6;
        
$offsetBase 6;

        if (isset(
$this->_info['exif']['ByteAlign']) && ($this->_info['exif']['ByteAlign'] == "Big Endian")) {
            
$isBigEndian true;
            
$aux "MM";
            
$pos $this->_putString($data$pos$aux);
        }
        else {
            
$isBigEndian false;
            
$aux "II";
            
$pos $this->_putString($data$pos$aux);
        }
        
$pos $this->_putShort($data$pos0x002A$isBigEndian);
        
$pos $this->_putLong($data$pos0x00000008$isBigEndian); // IFD0 Offset is always 8

        
$ifd0 =& $this->_getIFDEntries($isBigEndian'ifd0');
        
$ifd1 =& $this->_getIFDEntries($isBigEndian'ifd1');

        
$pos $this->_writeIFD($data$pos$offsetBase$ifd0$isBigEndiantrue);
        
$pos $this->_writeIFD($data$pos$offsetBase$ifd1$isBigEndianfalse);

        return 
$data;
    }

    
/*************************************************************/
    
function _writeIFD(&$data$pos$offsetBase, &$entries$isBigEndian$hasNext)
    {
        
$tiffData null;
        
$tiffDataOffsetPos = -1;

        
$entryCount count($entries);

        
$dataPos $pos + ($entryCount 12) + 4;
        
$pos $this->_putShort($data$pos$entryCount$isBigEndian);

        for (
$i 0$i $entryCount$i++) {
            
$tag $entries[$i]['tag'];
            
$type $entries[$i]['type'];

            if (
$type == -99) { // SubIFD
                
$pos $this->_putShort($data$pos$tag$isBigEndian);
                
$pos $this->_putShort($data$pos0x04$isBigEndian); // LONG
                
$pos $this->_putLong($data$pos0x01$isBigEndian); // Count = 1
                
$pos $this->_putLong($data$pos$dataPos $offsetBase$isBigEndian);

                
$dataPos $this->_writeIFD($data$dataPos$offsetBase$entries[$i]['value'], $isBigEndianfalse);
            }
            elseif (
$type == -98) { // TIFF Data
                
$pos $this->_putShort($data$pos$tag$isBigEndian);
                
$pos $this->_putShort($data$pos0x04$isBigEndian); // LONG
                
$pos $this->_putLong($data$pos0x01$isBigEndian); // Count = 1
                
$tiffDataOffsetPos $pos;
                
$pos $this->_putLong($data$pos0x00$isBigEndian); // For Now
                
$tiffData =& $entries[$i]['value'] ;
            }
            else { 
// Regular Entry
                
$pos $this->_putShort($data$pos$tag$isBigEndian);
                
$pos $this->_putShort($data$pos$type$isBigEndian);
                
$pos $this->_putLong($data$pos$entries[$i]['count'], $isBigEndian);
                if (
strlen($entries[$i]['value']) > 4) {
                    
$pos $this->_putLong($data$pos$dataPos $offsetBase$isBigEndian);
                    
$dataPos $this->_putString($data$dataPos$entries[$i]['value']);
                }
                else {
                    
$val str_pad($entries[$i]['value'], 4"\0");
                    
$pos $this->_putString($data$pos$val);
                }
            }
        }

        if (
$tiffData != null) {
            
$this->_putLong($data$tiffDataOffsetPos$dataPos $offsetBase$isBigEndian);
            
$dataPos $this->_putString($data$dataPos$tiffData);
        }

        if (
$hasNext) {
            
$pos $this->_putLong($data$pos$dataPos $offsetBase$isBigEndian);
        }
        else {
            
$pos $this->_putLong($data$pos0$isBigEndian);
        }

        return 
$dataPos;
    }

    
/*************************************************************/
    
function & _getIFDEntries($isBigEndian$mode)
    {
        
$EXIFNames $this->_exifTagNames($mode);
        
$EXIFTags $this->_exifNameTags($mode);
        
$EXIFTypeInfo $this->_exifTagTypes($mode);

        
$ifdEntries = array();
        
$entryCount 0;

        
reset($EXIFNames);
        while (list(
$tag$name) = each($EXIFNames)) {
            
$type $EXIFTypeInfo[$tag][0];
            
$count $EXIFTypeInfo[$tag][1];
            
$value null;

            if ((
$mode == 'ifd0') && ($tag == 0x8769)) {  // ExifIFDOffset
                
if (isset($this->_info['exif']['EXIFVersion'])) {
                    
$value =& $this->_getIFDEntries($isBigEndian"exif");
                    
$type = -99;
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'ifd0') && ($tag == 0x8825)) {  // GPSIFDOffset
                
if (isset($this->_info['exif']['GPSVersionID'])) {
                    
$value =& $this->_getIFDEntries($isBigEndian"gps");
                    
$type = -99;
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0111)) {  // TIFFStripOffsets
                
if (isset($this->_info['exif']['TIFFStrips'])) {
                    
$value =& $this->_info['exif']['TIFFStrips'];
                    
$type = -98;
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0117)) {  // TIFFStripByteCounts
                
if (isset($this->_info['exif']['TIFFStrips'])) {
                    
$value strlen($this->_info['exif']['TIFFStrips']);
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0201)) {  // TIFFJFIFOffset
                
if (isset($this->_info['exif']['JFIFThumbnail'])) {
                    
$value =& $this->_info['exif']['JFIFThumbnail'];
                    
$type = -98;
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'ifd1') && ($tag == 0x0202)) {  // TIFFJFIFLength
                
if (isset($this->_info['exif']['JFIFThumbnail'])) {
                    
$value strlen($this->_info['exif']['JFIFThumbnail']);
                }
                else {
                    
$value null;
                }
            }
            elseif ((
$mode == 'exif') && ($tag == 0xA005)) {  // InteropIFDOffset
                
if (isset($this->_info['exif']['InteroperabilityIndex'])) {
                    
$value =& $this->_getIFDEntries($isBigEndian"interop");
                    
$type = -99;
                }
                else {
                    
$value null;
                }
            }
            elseif (isset(
$this->_info['exif'][$name])) {
                
$origValue =& $this->_info['exif'][$name];

                
// This makes it easier to process variable size elements
                
if (!is_array($origValue) || isset($origValue['val'])) {
                    unset(
$origValue); // Break the reference
                    
$origValue = array(&$this->_info['exif'][$name]);
                }
                
$origCount count($origValue);

                if (
$origCount == ) {
                    
$type = -1;  // To ignore this field
                
}

                
$value " ";

                switch (
$type) {
                case 
1:    // UBYTE
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {

                        
$this->_putByte($value$j$origValue[$j]);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putByte($value$j0);
                        
$j++;
                    }
                    break;
                case 
2:    // ASCII
                    
$v strval($origValue[0]);
                    if ((
$count != 0) && (strlen($v) > $count)) {
                        
$v substr($v0$count);
                    }
                    elseif ((
$count 0) && (strlen($v) < $count)) {
                        
$v str_pad($v$count"\0");
                    }

                    
$count strlen($v);

                    
$this->_putString($value0$v);
                    break;
                case 
3:    // USHORT
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$this->_putShort($value$j 2$origValue[$j], $isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putShort($value$j 20$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
4:    // ULONG
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$this->_putLong($value$j 4$origValue[$j], $isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putLong($value$j 40$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
5:    // URATIONAL
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$v $origValue[$j];
                        if (
is_array($v)) {
                            
$a $v['num'];
                            
$b $v['den'];
                        }
                        else {
                            
$a 0;
                            
$b 0;
                            
// TODO: Allow other types and convert them
                        
}
                        
$this->_putLong($value$j 8$a$isBigEndian);
                        
$this->_putLong($value, ($j 8) + 4$b$isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putLong($value$j 80$isBigEndian);
                        
$this->_putLong($value, ($j 8) + 40$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
6:    // SBYTE
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$this->_putByte($value$j$origValue[$j]);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putByte($value$j0);
                        
$j++;
                    }
                    break;
                case 
7:    // UNDEFINED
                    
$v strval($origValue[0]);
                    if ((
$count != 0) && (strlen($v) > $count)) {
                        
$v substr($v0$count);
                    }
                    elseif ((
$count 0) && (strlen($v) < $count)) {
                        
$v str_pad($v$count"\0");
                    }

                    
$count strlen($v);

                    
$this->_putString($value0$v);
                    break;
                case 
8:    // SSHORT
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$this->_putShort($value$j 2$origValue[$j], $isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putShort($value$j 20$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
9:    // SLONG
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$this->_putLong($value$j 4$origValue[$j], $isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putLong($value$j 40$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
10:   // SRATIONAL
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$v $origValue[$j];
                        if (
is_array($v)) {
                            
$a $v['num'];
                            
$b $v['den'];
                        }
                        else {
                            
$a 0;
                            
$b 0;
                            
// TODO: Allow other types and convert them
                        
}

                        
$this->_putLong($value$j 8$a$isBigEndian);
                        
$this->_putLong($value, ($j 8) + 4$b$isBigEndian);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putLong($value$j 80$isBigEndian);
                        
$this->_putLong($value, ($j 8) + 40$isBigEndian);
                        
$j++;
                    }
                    break;
                case 
11:   // FLOAT
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$v strval($origValue[$j]);
                        if (
strlen($v) > 4) {
                            
$v substr($v04);
                        }
                        elseif (
strlen($v) < 4) {
                            
$v str_pad($v4"\0");
                        }
                        
$this->_putString($value$j 4$v);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putString($value$j 4"\0\0\0\0");
                        
$j++;
                    }
                    break;
                case 
12:   // DFLOAT
                    
if ($count == 0) {
                        
$count $origCount;
                    }

                    
$j 0;
                    while ((
$j $count) && ($j $origCount)) {
                        
$v strval($origValue[$j]);
                        if (
strlen($v) > 8) {
                            
$v substr($v08);
                        }
                        elseif (
strlen($v) < 8) {
                            
$v str_pad($v8"\0");
                        }
                        
$this->_putString($value$j 8$v);
                        
$j++;
                    }

                    while (
$j $count) {
                        
$this->_putString($value$j 8"\0\0\0\0\0\0\0\0");
                        
$j++;
                    }
                    break;
                default:
                    
$value null;
                    break;
                }
            }

            if (
$value != null) {
                
$ifdEntries[$entryCount] = array();
                
$ifdEntries[$entryCount]['tag'] = $tag;
                
$ifdEntries[$entryCount]['type'] = $type;
                
$ifdEntries[$entryCount]['count'] = $count;
                
$ifdEntries[$entryCount]['value'] = $value;

                
$entryCount++;
            }
        }

        return 
$ifdEntries;
    }

    
/*************************************************************/
    
function _parseMarkerAdobe()
    {
        if (!isset(
$this->_markers)) {
            
$this->_readJPEG();
        }

        if (
$this->_markers == null) {
            return 
false;
        }

        
$data null;
        
$count count($this->_markers);
        
// Look for APP13: IPTC / Photoshop data
        
for ($i 0$i $count$i++) {
            if (
$this->_markers[$i]['marker'] == 0xED) {
                
$signature $this->_getFixedString($this->_markers[$i]['data'], 014);
                if (
$signature == "Photoshop 3.0\0") {
                    
$data =& $this->_markers[$i]['data'];
                    break;
                }
            }
        }

        if (
$data == null) {
            
$this->_info['adobe'] = false;
            
$this->_info['iptc'] = false;
            return 
false;
        }
        
$pos 14;
        
$this->_info['adobe'] = array();
        
$this->_info['adobe']['raw'] = array();
        
$this->_info['iptc'] = array();

        
$datasize strlen($data);

        while (
$pos $datasize) {
            
$signature $this->_getFixedString($data$pos4);
            if (
$signature != '8BIM')
                return 
false;
            
$pos += 4;

            
$type $this->_getShort($data$pos);
            
$pos += 2;

            
$strlen $this->_getByte($data$pos);
            
$pos += 1;
            
$header '';
            for (
$i 0$i $strlen$i++) {
                
$header .= $data{$pos $i};
            }
            
$pos += $strlen - ($strlen 2);  // The string is padded to even length, counting the length byte itself

            
$length $this->_getLong($data$pos);
            
$pos += 4;

            
$basePos $pos;

            switch (
$type) {
            case 
0x0404// Caption (IPTC Data)
                
$pos $this->_readIPTC($data$pos);
                
// TODO: -re- this check fails all the time! Read comment on _readIPTC()!
                
if ($pos == false)
                    return 
false;
                break;
            case 
0x040A// CopyrightFlag
                
$this->_info['adobe']['CopyrightFlag'] = $this->_getByte($data$pos);
                
$pos += $length;
                break;
            case 
0x040B// ImageURL
                
$this->_info['adobe']['ImageURL'] = $this->_getFixedString($data$pos$length);
                
$pos += $length;
                break;
            case 
0x040C// Thumbnail
                
$aux $this->_getLong($data$pos);
                
$pos += 4;
                if (
$aux == 1) {
                    
$this->_info['adobe']['ThumbnailWidth'] = $this->_getLong($data$pos);
                    
$pos += 4;
                    
$this->_info['adobe']['ThumbnailHeight'] = $this->_getLong($data$pos);
                    
$pos += 4;

                    
$pos += 16// Skip some data

                    
$this->_info['adobe']['ThumbnailData'] = $this->_getFixedString($data$pos$length 28);
                    
$pos += $length 28;
                }
                break;
            default:
                break;
            }

            
// We save all blocks, even those we recognized
            
$label sprintf('8BIM_0x%04x'$type);
            
$this->_info['adobe']['raw'][$label] = array();
            
$this->_info['adobe']['raw'][$label]['type'] = $type;
            
$this->_info['adobe']['raw'][$label]['header'] = $header;
            
$this->_info['adobe']['raw'][$label]['data'] =& $this->_getFixedString($data$basePos$length);

            
$pos $basePos $length + ($length 2); // Even padding
        
}

    }

    
/**
     * Parses IPTC data from the given data fragment starting at the given position into some
     * internal structure.
     * See http://www.iptc.org/IIM/.
     *
     * @param string  the data to read
     * @param int     the position/offset into the data
     * @return int    the position/offset after the parsing, may be unchanged compared to the given
     *                position, if there is no IPTC data present
     */
    
function _readIPTC(&$data$pos 0)
    {
        
$totalLength strlen($data);

        
$IPTCTags =& $this->_iptcTagNames();

        while (
$pos < ($totalLength 5)) {
            
$lastPos $pos;
            
$tagmarker $this->_getByte($data$pos);
            if (
$tagmarker != 0x1C)
                return 
$pos;
            
$pos += 1;
            
$recordNumber $this->_getByte($data$pos);
            
$pos += 1;

            
$type $this->_getByte($data$pos);
            
$pos += 1;
            
$length $this->_getShort($data$pos);
            
$pos += 2;

            
/* Detect extended datasets (MSB is flag for standard/extended, rest is length) */
            
$isExtended = (bool)($length >> 15);
            
$length $length 0x7fff;
            if (
$isExtended) {
                
/*
                 * Only handle length up to 2^32 byte (can be up to 2^(2^15) byte long!).
                 * Thus we accept data which is up to 2^32 byte long.
                 */
                
$lengthCount $length;
                switch (
$lengthCount) {
                case 
1:
                    
$length $this->_getByte($data$pos);
                    break;
                case 
2:
                    
$length $this->_getShort($data$pos);
                    break;
                case 
3:
                    
$length = ($this->_getByte($data$pos) << 16)
                            + (
$this->_getByte($data$pos 1) << 8)
                            + 
$this->_getByte($data$pos 2);
                case 
4:
                    
$length $this->_getLong($data$pos);
                    break;
                default:
                    return 
$lastPos;
                }
                
$pos += $lengthCount;
            }

            
$basePos $pos;

            switch (
$recordNumber) {
            case 
0x02// Application Record
                
$label '';
                if (isset(
$IPTCTags[$type])) {
                    
$label $IPTCTags[$type];
                }
                else {
                    
$label sprintf('IPTC_0x%02x'$type);
                }

                if (
$label != '') {
                    if (isset(
$this->_info['iptc'][$label])) {
                        if (!
is_array($this->_info['iptc'][$label])) {
                            
$aux = array();
                            
$aux[0] = $this->_info['iptc'][$label];
                            
$this->_info['iptc'][$label] = $aux;
                        }
                        
$this->_info['iptc'][$label][ count($this->_info['iptc'][$label]) ] =
                            
$this->_getFixedString($data$pos$length);
                    }
                    else {
                        
$this->_info['iptc'][$label] = $this->_getFixedString($data$pos$length);
                    }
                }
                break;
            
// case 0x01: Envelope    
            // case 0x03: Digital newsphoto parameter
            // case 0x04: Not allocated
            // case 0x05: Not allocated
            // case 0x06: Abstract relationship
            // case 0x07: Pre-objectdata descriptor
            // case 0x08: Object data
            // case 0x09: Post-objectdata descriptor
            
default:  
                break; 
            }

            
$pos $basePos $length// No padding
        
}
        return 
$pos;
    }

    
/*************************************************************/
    
function & _createMarkerAdobe()
    {
        if (isset(
$this->_info['iptc'])) {
            if (!isset(
$this->_info['adobe'])) {
                
$this->_info['adobe'] = array();
            }
            if (!isset(
$this->_info['adobe']['raw'])) {
                
$this->_info['adobe']['raw'] = array();
            }
            if (!isset(
$this->_info['adobe']['raw']['8BIM_0x0404'])) {
                
$this->_info['adobe']['raw']['8BIM_0x0404'] = array();
            }
            
$this->_info['adobe']['raw']['8BIM_0x0404']['type'] = 0x0404;
            
$this->_info['adobe']['raw']['8BIM_0x0404']['header'] = "Caption";
            
$this->_info['adobe']['raw']['8BIM_0x0404']['data'] =& $this->_writeIPTC();
        }

        if (isset(
$this->_info['adobe']['raw']) && (count($this->_info['adobe']['raw']) > 0)) {
            
$data "Photoshop 3.0\0";
            
$pos 14;

            
reset($this->_info['adobe']['raw']);
            while (list(
$key) = each($this->_info['adobe']['raw'])) {
                
$pos $this->_write8BIM(
                            
$data,
                            
$pos,
                            
$this->_info['adobe']['raw'][$key]['type'],
                            
$this->_info['adobe']['raw'][$key]['header'],
                            
$this->_info['adobe']['raw'][$key]['data'] );
            }
        }

        return 
$data;
    }

    
/*************************************************************/
    
function _write8BIM(&$data$pos$type$header, &$value)
    {
        
$signature "8BIM";

        
$pos $this->_putString($data$pos$signature);
        
$pos $this->_putShort($data$pos$type);

        
$len strlen($header);

        
$pos $this->_putByte($data$pos$len);
        
$pos $this->_putString($data$pos$header);
        if ((
$len 2) == 0) {  // Even padding, including the length byte
            
$pos $this->_putByte($data$pos0);
        }

        
$len strlen($value);
        
$pos $this->_putLong($data$pos$len);
        
$pos $this->_putString($data$pos$value);
        if ((
$len 2) != 0) {  // Even padding
            
$pos $this->_putByte($data$pos0);
        }
        return 
$pos;
    }

    
/*************************************************************/
    
function & _writeIPTC()
    {
        
$data " ";
        
$pos 0;

        
$IPTCNames =& $this->_iptcNameTags();

        
reset($this->_info['iptc']);


        while (list(
$label) = each($this->_info['iptc'])) {
            
$value =& $this->_info['iptc'][$label];
            
$type = -1;

            if (isset(
$IPTCNames[$label])) {
                
$type $IPTCNames[$label];
            }
            elseif (
substr($label07) == "IPTC_0x") {
                
$type hexdec(substr($label72));
            }

            if (
$type != -1) {
                if (
is_array($value)) {
                    for (
$i 0$i count($value); $i++) {
                        
$pos $this->_writeIPTCEntry($data$pos$type$value[$i]);
                    }
                }
                else {
                    
$pos $this->_writeIPTCEntry($data$pos$type$value);
                }
            }
        }

        return 
$data;
    }

    
/*************************************************************/
    
function _writeIPTCEntry(&$data$pos$type, &$value)
    {
        
$pos $this->_putShort($data$pos0x1C02);
        
$pos $this->_putByte($data$pos$type);
        
$pos $this->_putShort($data$posstrlen($value));
        
$pos $this->_putString($data$pos$value);

        return 
$pos;
    }

    
/**
     * Returns an array of known EXIF tag codes and their associated names
     * for the given mode/section.
     *
     * EXIF builds upon the TIFF/JPEG specifications and extends them. TIFF/JPEG/EXIF
     * allow for different sections, which must be given as input to this method.
     *
     * ifd0    => Metadata for the primary image
     * ifd1    => Metadata for the secondary image (a thumbnail)
     * exif    => Camera meta data for the image
     * interop => Minmal metadata for interoperability
     * gps     => Metadata gained from a Global Positioning System
     *
     * ifd0 and ifd1 are defined by the TIFF specifiction. They often have the very same name,
     * only describing a property of the primary image vs. the same property of the thumbnail.
     *
     * Note, that currently the thumbnail metadata is prefixed wrongly with 'TIFF', this might
     * change in a future version (ifd0 data is also TIFF data).
     *
     * @param string  the EXIF section to return
     * @return array  an array with known tags; key is the tag number, value is the tag name
     */
    
function _exifTagNames($mode)
    {
        
$tags = array();

        if (
$mode == 'ifd0') {
            
$tags[0x010E] = 'ImageDescription';
            
$tags[0x010F] = 'Make';
            
$tags[0x0110] = 'Model';
            
$tags[0x0112] = 'Orientation';
            
$tags[0x011A] = 'XResolution';
            
$tags[0x011B] = 'YResolution';
            
$tags[0x0128] = 'ResolutionUnit';
            
$tags[0x0131] = 'Software';
            
$tags[0x0132] = 'DateTime';
            
$tags[0x013B] = 'Artist';
            
$tags[0x013E] = 'WhitePoint';
            
$tags[0x013F] = 'PrimaryChromaticities';
            
$tags[0x0211] = 'YCbCrCoefficients';
            
$tags[0x0212] = 'YCbCrSubSampling';
            
$tags[0x0213] = 'YCbCrPositioning';
            
$tags[0x0214] = 'ReferenceBlackWhite';
            
$tags[0x8298] = 'Copyright';
            
$tags[0x8769] = 'ExifIFDOffset';
            
$tags[0x8825] = 'GPSIFDOffset';
        }
        if (
$mode == 'ifd1') {
            
$tags[0x00FE] = 'TIFFNewSubfileType';
            
$tags[0x00FF] = 'TIFFSubfileType';
            
$tags[0x0100] = 'TIFFImageWidth';
            
$tags[0x0101] = 'TIFFImageHeight';
            
$tags[0x0102] = 'TIFFBitsPerSample';
            
$tags[0x0103] = 'TIFFCompression';
            
$tags[0x0106] = 'TIFFPhotometricInterpretation';
            
$tags[0x0107] = 'TIFFThreshholding';
            
$tags[0x0108] = 'TIFFCellWidth';
            
$tags[0x0109] = 'TIFFCellLength';
            
$tags[0x010A] = 'TIFFFillOrder';
            
$tags[0x010E] = 'TIFFImageDescription';
            
$tags[0x010F] = 'TIFFMake';
            
$tags[0x0110] = 'TIFFModel';
            
$tags[0x0111] = 'TIFFStripOffsets';
            
$tags[0x0112] = 'TIFFOrientation';
            
$tags[0x0115] = 'TIFFSamplesPerPixel';
            
$tags[0x0116] = 'TIFFRowsPerStrip';
            
$tags[0x0117] = 'TIFFStripByteCounts';
            
$tags[0x0118] = 'TIFFMinSampleValue';
            
$tags[0x0119] = 'TIFFMaxSampleValue';
            
$tags[0x011A] = 'TIFFXResolution';
            
$tags[0x011B] = 'TIFFYResolution';
            
$tags[0x011C] = 'TIFFPlanarConfiguration';
            
$tags[0x0122] = 'TIFFGrayResponseUnit';
            
$tags[0x0123] = 'TIFFGrayResponseCurve';
            
$tags[0x0128] = 'TIFFResolutionUnit';
            
$tags[0x0131] = 'TIFFSoftware';
            
$tags[0x0132] = 'TIFFDateTime';
            
$tags[0x013B] = 'TIFFArtist';
            
$tags[0x013C] = 'TIFFHostComputer';
            
$tags[0x0140] = 'TIFFColorMap';
            
$tags[0x0152] = 'TIFFExtraSamples';
            
$tags[0x0201] = 'TIFFJFIFOffset';
            
$tags[0x0202] = 'TIFFJFIFLength';
            
$tags[0x0211] = 'TIFFYCbCrCoefficients';
            
$tags[0x0212] = 'TIFFYCbCrSubSampling';
            
$tags[0x0213] = 'TIFFYCbCrPositioning';
            
$tags[0x0214] = 'TIFFReferenceBlackWhite';
            
$tags[0x8298] = 'TIFFCopyright';
            
$tags[0x9286] = 'TIFFUserComment';
        }
        elseif (
$mode == 'exif') {
            
$tags[0x829A] = 'ExposureTime';
            
$tags[0x829D] = 'FNumber';
            
$tags[0x8822] = 'ExposureProgram';
            
$tags[0x8824] = 'SpectralSensitivity';
            
$tags[0x8827] = 'ISOSpeedRatings';
            
$tags[0x8828] = 'OECF';
            
$tags[0x9000] = 'EXIFVersion';
            
$tags[0x9003] = 'DatetimeOriginal';
            
$tags[0x9004] = 'DatetimeDigitized';
            
$tags[0x9101] = 'ComponentsConfiguration';
            
$tags[0x9102] = 'CompressedBitsPerPixel';
            
$tags[0x9201] = 'ShutterSpeedValue';
            
$tags[0x9202] = 'ApertureValue';
            
$tags[0x9203] = 'BrightnessValue';
            
$tags[0x9204] = 'ExposureBiasValue';
            
$tags[0x9205] = 'MaxApertureValue';
            
$tags[0x9206] = 'SubjectDistance';
            
$tags[0x9207] = 'MeteringMode';
            
$tags[0x9208] = 'LightSource';
            
$tags[0x9209] = 'Flash';
            
$tags[0x920A] = 'FocalLength';
            
$tags[0x927C] = 'MakerNote';
            
$tags[0x9286] = 'UserComment';
            
$tags[0x9290] = 'SubSecTime';
            
$tags[0x9291] = 'SubSecTimeOriginal';
            
$tags[0x9292] = 'SubSecTimeDigitized';
            
$tags[0xA000] = 'FlashPixVersion';
            
$tags[0xA001] = 'ColorSpace';
            
$tags[0xA002] = 'PixelXDimension';
            
$tags[0xA003] = 'PixelYDimension';
            
$tags[0xA004] = 'RelatedSoundFile';
            
$tags[0xA005] = 'InteropIFDOffset';
            
$tags[0xA20B] = 'FlashEnergy';
            
$tags[0xA20C] = 'SpatialFrequencyResponse';
            
$tags[0xA20E] = 'FocalPlaneXResolution';
            
$tags[0xA20F] = 'FocalPlaneYResolution';
            
$tags[0xA210] = 'FocalPlaneResolutionUnit';
            
$tags[0xA214] = 'SubjectLocation';
            
$tags[0xA215] = 'ExposureIndex';
            
$tags[0xA217] = 'SensingMethod';
            
$tags[0xA300] = 'FileSource';
            
$tags[0xA301] = 'SceneType';
            
$tags[0xA302] = 'CFAPattern';
        }
        elseif (
$mode == 'interop') {
            
$tags[0x0001] = 'InteroperabilityIndex';
            
$tags[0x0002] = 'InteroperabilityVersion';
            
$tags[0x1000] = 'RelatedImageFileFormat';
            
$tags[0x1001] = 'RelatedImageWidth';
            
$tags[0x1002] = 'RelatedImageLength';
        }
        elseif (
$mode == 'gps') {
            
$tags[0x0000] = 'GPSVersionID';
            
$tags[0x0001] = 'GPSLatitudeRef';
            
$tags[0x0002] = 'GPSLatitude';
            
$tags[0x0003] = 'GPSLongitudeRef';
            
$tags[0x0004] = 'GPSLongitude';
            
$tags[0x0005] = 'GPSAltitudeRef';
            
$tags[0x0006] = 'GPSAltitude';
            
$tags[0x0007] = 'GPSTimeStamp';
            
$tags[0x0008] = 'GPSSatellites';
            
$tags[0x0009] = 'GPSStatus';
            
$tags[0x000A] = 'GPSMeasureMode';
            
$tags[0x000B] = 'GPSDOP';
            
$tags[0x000C] = 'GPSSpeedRef';
            
$tags[0x000D] = 'GPSSpeed';
            
$tags[0x000E] = 'GPSTrackRef';
            
$tags[0x000F] = 'GPSTrack';
            
$tags[0x0010] = 'GPSImgDirectionRef';
            
$tags[0x0011] = 'GPSImgDirection';
            
$tags[0x0012] = 'GPSMapDatum';
            
$tags[0x0013] = 'GPSDestLatitudeRef';
            
$tags[0x0014] = 'GPSDestLatitude';
            
$tags[0x0015] = 'GPSDestLongitudeRef';
            
$tags[0x0016] = 'GPSDestLongitude';
            
$tags[0x0017] = 'GPSDestBearingRef';
            
$tags[0x0018] = 'GPSDestBearing';
            
$tags[0x0019] = 'GPSDestDistanceRef';
            
$tags[0x001A] = 'GPSDestDistance';
        }

        return 
$tags;
    }

    
/*************************************************************/
    
function _exifTagTypes($mode)
    {
        
$tags = array();

        if (
$mode == 'ifd0') {
            
$tags[0x010E] = array(20); // ImageDescription -> ASCII, Any
            
$tags[0x010F] = array(20); // Make -> ASCII, Any
            
$tags[0x0110] = array(20); // Model -> ASCII, Any
            
$tags[0x0112] = array(31); // Orientation -> SHORT, 1
            
$tags[0x011A] = array(51); // XResolution -> RATIONAL, 1
            
$tags[0x011B] = array(51); // YResolution -> RATIONAL, 1
            
$tags[0x0128] = array(31); // ResolutionUnit -> SHORT
            
$tags[0x0131] = array(20); // Software -> ASCII, Any
            
$tags[0x0132] = array(220); // DateTime -> ASCII, 20
            
$tags[0x013B] = array(20); // Artist -> ASCII, Any
            
$tags[0x013E] = array(52); // WhitePoint -> RATIONAL, 2
            
$tags[0x013F] = array(56); // PrimaryChromaticities -> RATIONAL, 6
            
$tags[0x0211] = array(53); // YCbCrCoefficients -> RATIONAL, 3
            
$tags[0x0212] = array(32); // YCbCrSubSampling -> SHORT, 2
            
$tags[0x0213] = array(31); // YCbCrPositioning -> SHORT, 1
            
$tags[0x0214] = array(56); // ReferenceBlackWhite -> RATIONAL, 6
            
$tags[0x8298] = array(20); // Copyright -> ASCII, Any
            
$tags[0x8769] = array(41); // ExifIFDOffset -> LONG, 1
            
$tags[0x8825] = array(41); // GPSIFDOffset -> LONG, 1
        
}
        if (
$mode == 'ifd1') {
            
$tags[0x00FE] = array(41); // TIFFNewSubfileType -> LONG, 1
            
$tags[0x00FF] = array(31); // TIFFSubfileType -> SHORT, 1
            
$tags[0x0100] = array(41); // TIFFImageWidth -> LONG (or SHORT), 1
            
$tags[0x0101] = array(41); // TIFFImageHeight -> LONG (or SHORT), 1
            
$tags[0x0102] = array(33); // TIFFBitsPerSample -> SHORT, 3
            
$tags[0x0103] = array(31); // TIFFCompression -> SHORT, 1
            
$tags[0x0106] = array(31); // TIFFPhotometricInterpretation -> SHORT, 1
            
$tags[0x0107] = array(31); // TIFFThreshholding -> SHORT, 1
            
$tags[0x0108] = array(31); // TIFFCellWidth -> SHORT, 1
            
$tags[0x0109] = array(31); // TIFFCellLength -> SHORT, 1
            
$tags[0x010A] = array(31); // TIFFFillOrder -> SHORT, 1
            
$tags[0x010E] = array(20); // TIFFImageDescription -> ASCII, Any
            
$tags[0x010F] = array(20); // TIFFMake -> ASCII, Any
            
$tags[0x0110] = array(20); // TIFFModel -> ASCII, Any
            
$tags[0x0111] = array(40); // TIFFStripOffsets -> LONG (or SHORT), Any (one per strip)
            
$tags[0x0112] = array(31); // TIFFOrientation -> SHORT, 1
            
$tags[0x0115] = array(31); // TIFFSamplesPerPixel -> SHORT, 1
            
$tags[0x0116] = array(41); // TIFFRowsPerStrip -> LONG (or SHORT), 1
            
$tags[0x0117] = array(40); // TIFFStripByteCounts -> LONG (or SHORT), Any (one per strip)
            
$tags[0x0118] = array(30); // TIFFMinSampleValue -> SHORT, Any (SamplesPerPixel)
            
$tags[0x0119] = array(30); // TIFFMaxSampleValue -> SHORT, Any (SamplesPerPixel)
            
$tags[0x011A] = array(51); // TIFFXResolution -> RATIONAL, 1
            
$tags[0x011B] = array(51); // TIFFYResolution -> RATIONAL, 1
            
$tags[0x011C] = array(31); // TIFFPlanarConfiguration -> SHORT, 1
            
$tags[0x0122] = array(31); // TIFFGrayResponseUnit -> SHORT, 1
            
$tags[0x0123] = array(30); // TIFFGrayResponseCurve -> SHORT, Any (2^BitsPerSample)
            
$tags[0x0128] = array(31); // TIFFResolutionUnit -> SHORT, 1
            
$tags[0x0131] = array(20); // TIFFSoftware -> ASCII, Any
            
$tags[0x0132] = array(220); // TIFFDateTime -> ASCII, 20
            
$tags[0x013B] = array(20); // TIFFArtist -> ASCII, Any
            
$tags[0x013C] = array(20); // TIFFHostComputer -> ASCII, Any
            
$tags[0x0140] = array(30); // TIFFColorMap -> SHORT, Any (3 * 2^BitsPerSample)
            
$tags[0x0152] = array(30); // TIFFExtraSamples -> SHORT, Any (SamplesPerPixel - 3)
            
$tags[0x0201] = array(41); // TIFFJFIFOffset -> LONG, 1
            
$tags[0x0202] = array(41); // TIFFJFIFLength -> LONG, 1
            
$tags[0x0211] = array(53); // TIFFYCbCrCoefficients -> RATIONAL, 3
            
$tags[0x0212] = array(32); // TIFFYCbCrSubSampling -> SHORT, 2
            
$tags[0x0213] = array(31); // TIFFYCbCrPositioning -> SHORT, 1
            
$tags[0x0214] = array(56); // TIFFReferenceBlackWhite -> RATIONAL, 6
            
$tags[0x8298] = array(20); // TIFFCopyright -> ASCII, Any
            
$tags[0x9286] = array(20); // TIFFUserComment -> ASCII, Any
        
}
        elseif (
$mode == 'exif') {
            
$tags[0x829A] = array(51); // ExposureTime -> RATIONAL, 1
            
$tags[0x829D] = array(51); // FNumber -> RATIONAL, 1
            
$tags[0x8822] = array(31); // ExposureProgram -> SHORT, 1
            
$tags[0x8824] = array(20); // SpectralSensitivity -> ASCII, Any
            
$tags[0x8827] = array(30); // ISOSpeedRatings -> SHORT, Any
            
$tags[0x8828] = array(70); // OECF -> UNDEFINED, Any
            
$tags[0x9000] = array(74); // EXIFVersion -> UNDEFINED, 4
            
$tags[0x9003] = array(220); // DatetimeOriginal -> ASCII, 20
            
$tags[0x9004] = array(220); // DatetimeDigitized -> ASCII, 20
            
$tags[0x9101] = array(74); // ComponentsConfiguration -> UNDEFINED, 4
            
$tags[0x9102] = array(51); // CompressedBitsPerPixel -> RATIONAL, 1
            
$tags[0x9201] = array(101); // ShutterSpeedValue -> SRATIONAL, 1
            
$tags[0x9202] = array(51); // ApertureValue -> RATIONAL, 1
            
$tags[0x9203] = array(101); // BrightnessValue -> SRATIONAL, 1
            
$tags[0x9204] = array(101); // ExposureBiasValue -> SRATIONAL, 1
            
$tags[0x9205] = array(51); // MaxApertureValue -> RATIONAL, 1
            
$tags[0x9206] = array(51); // SubjectDistance -> RATIONAL, 1
            
$tags[0x9207] = array(31); // MeteringMode -> SHORT, 1
            
$tags[0x9208] = array(31); // LightSource -> SHORT, 1
            
$tags[0x9209] = array(31); // Flash -> SHORT, 1
            
$tags[0x920A] = array(51); // FocalLength -> RATIONAL, 1
            
$tags[0x927C] = array(70); // MakerNote -> UNDEFINED, Any
            
$tags[0x9286] = array(70); // UserComment -> UNDEFINED, Any
            
$tags[0x9290] = array(20); // SubSecTime -> ASCII, Any
            
$tags[0x9291] = array(20); // SubSecTimeOriginal -> ASCII, Any
            
$tags[0x9292] = array(20); // SubSecTimeDigitized -> ASCII, Any
            
$tags[0xA000] = array(74); // FlashPixVersion -> UNDEFINED, 4
            
$tags[0xA001] = array(31); // ColorSpace -> SHORT, 1
            
$tags[0xA002] = array(41); // PixelXDimension -> LONG (or SHORT), 1
            
$tags[0xA003] = array(41); // PixelYDimension -> LONG (or SHORT), 1
            
$tags[0xA004] = array(213); // RelatedSoundFile -> ASCII, 13
            
$tags[0xA005] = array(41); // InteropIFDOffset -> LONG, 1
            
$tags[0xA20B] = array(51); // FlashEnergy -> RATIONAL, 1
            
$tags[0xA20C] = array(70); // SpatialFrequencyResponse -> UNDEFINED, Any
            
$tags[0xA20E] = array(51); // FocalPlaneXResolution -> RATIONAL, 1
            
$tags[0xA20F] = array(51); // FocalPlaneYResolution -> RATIONAL, 1
            
$tags[0xA210] = array(31); // FocalPlaneResolutionUnit -> SHORT, 1
            
$tags[0xA214] = array(32); // SubjectLocation -> SHORT, 2
            
$tags[0xA215] = array(51); // ExposureIndex -> RATIONAL, 1
            
$tags[0xA217] = array(31); // SensingMethod -> SHORT, 1
            
$tags[0xA300] = array(71); // FileSource -> UNDEFINED, 1
            
$tags[0xA301] = array(71); // SceneType -> UNDEFINED, 1
            
$tags[0xA302] = array(70); // CFAPattern -> UNDEFINED, Any
        
}
        elseif (
$mode == 'interop') {
            
$tags[0x0001] = array(20); // InteroperabilityIndex -> ASCII, Any
            
$tags[0x0002] = array(74); // InteroperabilityVersion -> UNKNOWN, 4
            
$tags[0x1000] = array(20); // RelatedImageFileFormat -> ASCII, Any
            
$tags[0x1001] = array(41); // RelatedImageWidth -> LONG (or SHORT), 1
            
$tags[0x1002] = array(41); // RelatedImageLength -> LONG (or SHORT), 1
        
}
        elseif (
$mode == 'gps') {
            
$tags[0x0000] = array(14); // GPSVersionID -> BYTE, 4
            
$tags[0x0001] = array(22); // GPSLatitudeRef -> ASCII, 2
            
$tags[0x0002] = array(53); // GPSLatitude -> RATIONAL, 3
            
$tags[0x0003] = array(22); // GPSLongitudeRef -> ASCII, 2
            
$tags[0x0004] = array(53); // GPSLongitude -> RATIONAL, 3
            
$tags[0x0005] = array(22); // GPSAltitudeRef -> ASCII, 2
            
$tags[0x0006] = array(51); // GPSAltitude -> RATIONAL, 1
            
$tags[0x0007] = array(53); // GPSTimeStamp -> RATIONAL, 3
            
$tags[0x0008] = array(20); // GPSSatellites -> ASCII, Any
            
$tags[0x0009] = array(22); // GPSStatus -> ASCII, 2
            
$tags[0x000A] = array(22); // GPSMeasureMode -> ASCII, 2
            
$tags[0x000B] = array(51); // GPSDOP -> RATIONAL, 1
            
$tags[0x000C] = array(22); // GPSSpeedRef -> ASCII, 2
            
$tags[0x000D] = array(51); // GPSSpeed -> RATIONAL, 1
            
$tags[0x000E] = array(22); // GPSTrackRef -> ASCII, 2
            
$tags[0x000F] = array(51); // GPSTrack -> RATIONAL, 1
            
$tags[0x0010] = array(22); // GPSImgDirectionRef -> ASCII, 2
            
$tags[0x0011] = array(51); // GPSImgDirection -> RATIONAL, 1
            
$tags[0x0012] = array(20); // GPSMapDatum -> ASCII, Any
            
$tags[0x0013] = array(22); // GPSDestLatitudeRef -> ASCII, 2
            
$tags[0x0014] = array(53); // GPSDestLatitude -> RATIONAL, 3
            
$tags[0x0015] = array(22); // GPSDestLongitudeRef -> ASCII, 2
            
$tags[0x0016] = array(53); // GPSDestLongitude -> RATIONAL, 3
            
$tags[0x0017] = array(22); // GPSDestBearingRef -> ASCII, 2
            
$tags[0x0018] = array(51); // GPSDestBearing -> RATIONAL, 1
            
$tags[0x0019] = array(22); // GPSDestDistanceRef -> ASCII, 2
            
$tags[0x001A] = array(51); // GPSDestDistance -> RATIONAL, 1
        
}

        return 
$tags;
    }

    
/**
     * Returns an array of known EXIF tag names and their associated codes
     * for the given mode/section.
     *
     * See _exifTagNames() for explanation.
     *
     * @param string  the EXIF section to return
     * @return array  an array with known tags; key is the tag name, value is the tag number/code
     */
    
function _exifNameTags($mode)
    {
        
$tags $this->_exifTagNames($mode);
        return 
$this->_names2Tags($tags);
    }

    
/**
     * Returns an array of known IPTC tag codes and their associated names.
     *
     * @return array  an array with known tags; key is the tag number, value is the tag name
     */
    
function &_iptcTagNames()
    {
        
$tags = array();
        
$tags[0x05] = 'ObjectName'// 64 bytes max
        
$tags[0x0A] = 'CopyrightFlag'// Urgency in IIMV4.1, 1 byte, numeric character, 1 = most urgent
        
$tags[0x0F] = 'Category'// deprecated, 3 bytes max
        
$tags[0x14] = 'SupplementalCategories'// deprecated, repeatable, 32 bytes max
        
$tags[0x19] = 'Keywords'// repeatable, 64 bytes max
        
$tags[0x28] = 'SpecialInstructions'// 256 bytes max
        
$tags[0x37] = 'DateCreated'// 8 bytes CCYYMMDD
        
$tags[0x3C] = 'TimeCreated'// 11 bytes HHMMSS+hhmm
        
$tags[0x50] = 'Byline'// repeatable, 32 bytes max
        
$tags[0x55] = 'BylineTitle'// repeatable, 32 bytes max
        
$tags[0x5A] = 'City'// 32 bytes max
        
$tags[0x5F] = 'ProvinceState'// 32 bytes max
        
$tags[0x65] = 'CountryName'// 64 bytes max
        
$tags[0x67] = 'OriginalTransmissionReference'// 32 bytes max
        
$tags[0x69] = 'Headline'// 256 bytes max
        
$tags[0x6E] = 'Credit'// 32 bytes max, provider of data, not neccessarily owner/creator
        
$tags[0x73] = 'Source'// 32 bytes max, original owner of intellectual content
        
$tags[0x74] = 'CopyrightNotice'// 128 bytes max
        
$tags[0x78] = 'Caption'// 2000 bytes max, abstract of object
        
$tags[0x7A] = 'CaptionWriter'// 32 bytes max

        //$tags[0x07] = 'EditStatus'; // 64 bytes max
        //$tags[0x0C] = 'SubjectReference'; // Repeatable, 13-236 bytes
        //$tags[0x16] = 'FixtureIdentifier'; // 32 bytes max
        //$tags[0x1A] = 'ContentLocationCode'; // repeatable, 3 bytes
        //$tags[0x1B] = 'ContentLocationName'; // repeatable, 64 bytes
        //$tags[0x1E] = 'ReleaseDate'; // 8 bytes CCYYMMDD
        //$tags[0x23] = 'ReleaseTime'; // 11 bytes HHMMSS+hhmm
        //$tags[0x25] = 'ExpirationDate'; // 8 bytes CCYYMMDD
        //$tags[0x26] = 'ExpirationTime'; // 11 bytes HHMMSS+hhmm
        //$tags[0x2D] = 'ReferenceService';
        //$tags[0x2F] = 'ReferenceDate';
        //$tags[0x32] = 'ReferenceNumber';
        //$tags[0x3E] = 'DigitalCreationDate'; // 8 bytes CCYYMMDD
        //$tags[0x3F] = 'DigitalCreationTime'; // 11 bytes HHMMSS+hhmm
        //$tags[0x41] = 'OriginatingProgram'; // 32 bytes max
        //$tags[0x46] = 'ProgramVersion'; // 10 bytes max
        //$tags[0x4B] = 'ObjectCycle';
        //$tags[0x5C] = 'Sublocation'; // 32 bytes max
        //$tags[0x64] = 'CountryCode'; // 3 bytes
        //$tags[0x76] = 'Contact'; // repeatable, 128 bytes max, person/organisation haveing background info
        //$tags[0x7D] = 'RasterizedCaption';
        //$tags[0x82] = 'ImageType';
        //$tags[0x83] = 'ImageOrientation';
        //$tags[0x87] = 'LanguagIdentifier';
        //$tags[0x96] = 'AudioType';
        // ...

        
return $tags;
    }

    
/**
     * Returns an array of known IPTC tag names and their associated codes.
     *
     * @return array  an array with known tags; key is the tag name, value is the tag code
     */
    
function & _iptcNameTags()
    {
        
$tags $this->_iptcTagNames();
        
$ret $this->_names2Tags($tags);
        return 
$ret;
    }

    
/**
     * Exchanges key and value in an associative array. The resulting array will be in the
     * same order as the given array.
     *
     * Note, that the values in the given array should be unique, else the returend array
     * will miss some entries.
     *
     * @param array  An associative array
     * @return array  The array with key/values flipped.
     */
    
function _names2Tags($tags2Names)
    {
        
$names2Tags = array();
        
reset($tags2Names);
        while (list(
$tag$name) = each($tags2Names)) {
            
$names2Tags[$name] = $tag;
        }

        return 
$names2Tags;
    }

    
/**
     * Gets a byte out of the given data at the given position.
     *
     * @param string  the data to process
     * @param int     the offset of the byte to extract
     * @return int    the byte value
     */
    
function _getByte(&$data$pos)
    {
        return 
ord($data{$pos});
    }

    
/**
     * Sets a byte of the given data at the given position to the given value.
     *
     * @param string  the data to process
     * @param int     the offset of the byte to write
     * @param int     the byte value to set into the data
     * @return int    the next available position
     */
    
function _putByte(&$data$pos$val)
    {
        
$val intval($val);

        
$data{$pos} = chr($val);

        return 
$pos 1;
    }

    
/**
     * Gets a short (2 bytes) out of the given data at the given position.
     *
     * @param string  the data to process
     * @param int     the offset of the short to extract
     * @param boolean flag indicating big endianess
     * @return int    the short value
     */
    
function _getShort(&$data$pos$bigEndian true)
    {
        if (
$bigEndian) {
            return (
ord($data{$pos}) << 8)
                   + 
ord($data{$pos 1});
        }
        else {
            return 
ord($data{$pos})
                   + (
ord($data{$pos 1}) << 8);
        }
    }

    
/**
     * Sets a short (2 bytes) of the given data at the given position to the given value.
     *
     * @param string  the data to process
     * @param int     the offset of the short to write
     * @param int     the short value to set into the data
     * @param boolean flag indicating big endianess
     * @return int    the next available position
     */
    
function _putShort(&$data$pos 0$val$bigEndian true)
    {
        
$val intval($val);

        if (
$bigEndian) {
            
$data{$pos 0} = chr(($val 0x0000FF00) >> 8);
            
$data{$pos 1} = chr(($val 0x000000FF) >> 0);
        }
        else {
            
$data{$pos 0} = chr(($val 0x00FF) >> 0);
            
$data{$pos 1} = chr(($val 0xFF00) >> 8);
        }

        return 
$pos 2;
    }

    
/**
     * Gets a long (4 bytes) out of the given data at the given position.
     *
     * @param string  the data to process
     * @param int     the offset of the long to extract
     * @param boolean flag indicating big endianess
     * @return int    the long value
     */
    
function _getLong(&$data$pos$bigEndian true)
    {
        if (
$bigEndian) {
            return (
ord($data{$pos}) << 24)
                   + (
ord($data{$pos 1}) << 16)
                   + (
ord($data{$pos 2}) << 8)
                   + 
ord($data{$pos 3});
        }
        return 
ord($data{$pos})
               + (
ord($data{$pos 1}) << 8)
               + (
ord($data{$pos 2}) << 16)
               + (
ord($data{$pos 3}) << 24);
    }

    
/**
     * Sets a long (4 bytes) of the given data at the given position to the given value.
     *
     * @param string  the data to process
     * @param int     the offset of the long to write
     * @param int     the long value to set into the data
     * @param boolean flag indicating big endianess
     * @return int    the next available position
     */
    
function _putLong(&$data$pos$val$bigEndian true)
    {
        
$val intval($val);

        if (
$bigEndian) {
            
$data{$pos 0} = chr(($val 0xFF000000) >> 24);
            
$data{$pos 1} = chr(($val 0x00FF0000) >> 16);
            
$data{$pos 2} = chr(($val 0x0000FF00) >> 8);
            
$data{$pos 3} = chr(($val 0x000000FF) >> 0);
        }
        else {
            
$data{$pos 0} = chr(($val 0x000000FF) >> 0);
            
$data{$pos 1} = chr(($val 0x0000FF00) >> 8);
            
$data{$pos 2} = chr(($val 0x00FF0000) >> 16);
            
$data{$pos 3} = chr(($val 0xFF000000) >> 24);
        }

        return 
$pos 4;
    }

    
/*************************************************************/
    
function & _getNullString(&$data$pos)
    {
        
$str '';
        
$max strlen($data);

        while (
$pos $max) {
            if (
ord($data{$pos}) == 0) {
                return 
$str;
            }
            else {
                
$str .= $data{$pos};
            }
            
$pos++;
        }

        return 
$str;
    }

    
/**
     * Gets the given lenght string/bytes out of the given data starting at the given position.
     * If a length isn't given all available data is returned.
     *
     * @param string  the data to extract part of
     * @param int     the start position of extraction
     * @param int     the length of the string to extract
     * @return string the extracted string
     */
    
function & _getFixedString(&$data$pos$length = -1)
    {
        if (
$length == -1) {
            
$length strlen($data) - $pos;
        }

        
$ret substr($data$pos$length);
        return 
$ret;
    }

    
/*************************************************************/
    
function _putString(&$data$pos, &$str)
    {
        
$len strlen($str);
        for (
$i 0$i $len$i++) {
          
$data{$pos $i} = $str{$i};
        }

        return 
$pos $len;
    }

    
/*************************************************************/
    
function _hexDump(&$data$start 0$length = -1)
    {
        if ((
$length == -1) || (($length $start) > strlen($data))) {
            
$end strlen($data);
        }
        else {
            
$end $start $length;
        }

        
$ascii '';
        
$count 0;

        echo 
"<tt>\n";

        while (
$start $end) {
            if ((
$count 16) == 0) {
                echo 
sprintf('%04d'$count) . ': ';
            }

            
$c ord($data{$start});
            
$count++;
            
$start++;

            
$aux dechex($c);
            if (
strlen($aux) == 1)
                echo 
'0';
            echo 
$aux ' ';

            if (
$c == 60)
                
$ascii .= '&lt;';
            elseif (
$c == 62)
                
$ascii .= '&gt;';
            elseif (
$c == 32)
                
$ascii .= '&nbsp;';
            elseif (
$c 32)
                
$ascii .= chr($c);
            else
                
$ascii .= '.';

            if ((
$count 4) == 0) {
                echo 
' - ';
            }

            if ((
$count 16) == 0) {
                echo 
': ' $ascii "<br>\n";
                
$ascii '';
            }
        }

        if (
$ascii != '') {
            while ((
$count 16) != 0) {
                echo 
'-- ';
                
$count++;
                if ((
$count 4) == 0) {
                    echo 
' - ';
                }
            }
            echo 
': ' $ascii "<br>\n";
        }

        echo 
"</tt>\n";
    }

/*****************************************************************/
}
?>

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.042 ]--