home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / File / Gettext / MO.php next >
Encoding:
PHP Script  |  2008-07-02  |  8.4 KB  |  332 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * File::Gettext
  6.  * 
  7.  * PHP versions 4 and 5
  8.  *
  9.  * @category   FileFormats
  10.  * @package    File_Gettext
  11.  * @author     Michael Wallner <mike@php.net>
  12.  * @copyright  2004-2005 Michael Wallner
  13.  * @license    BSD, revised
  14.  * @version    CVS: $Id: MO.php,v 1.8 2006/01/07 09:45:25 mike Exp $
  15.  * @link       http://pear.php.net/package/File_Gettext
  16.  */
  17.  
  18. /**
  19.  * Requires File_Gettext
  20.  */
  21. require_once 'File/Gettext.php';
  22.  
  23. /** 
  24.  * File_Gettext_MO
  25.  * 
  26.  * GNU MO file reader and writer.
  27.  *
  28.  * @author      Michael Wallner <mike@php.net>
  29.  * @version     $Revision: 1.8 $
  30.  * @access      public
  31.  */
  32. class File_Gettext_MO extends File_Gettext
  33. {
  34.     /**
  35.      * file handle
  36.      * 
  37.      * @access  private
  38.      * @var     resource
  39.      */
  40.     var $_handle = null;
  41.     
  42.     /**
  43.      * big endianess
  44.      * 
  45.      * Whether to write with big endian byte order.
  46.      * 
  47.      * @access  public
  48.      * @var     bool
  49.      */
  50.     var $writeBigEndian = false;
  51.     
  52.     /**
  53.      * Constructor
  54.      *
  55.      * @access  public
  56.      * @return  object      File_Gettext_MO
  57.      * @param   string      $file   path to GNU MO file
  58.      */
  59.     function File_Gettext_MO($file = '')
  60.     {
  61.         $this->file = $file;
  62.     }
  63.  
  64.     /**
  65.      * _read
  66.      *
  67.      * @access  private
  68.      * @return  mixed
  69.      * @param   int     $bytes
  70.      */
  71.     function _read($bytes = 1)
  72.     {
  73.         if (0 < $bytes = abs($bytes)) {
  74.             return fread($this->_handle, $bytes);
  75.         }
  76.         return null;
  77.     }
  78.     
  79.     /**
  80.      * _readInt
  81.      *
  82.      * @access  private
  83.      * @return  int
  84.      * @param   bool    $bigendian
  85.      */
  86.     function _readInt($bigendian = false)
  87.     {
  88.         return current($array = unpack($bigendian ? 'N' : 'V', $this->_read(4)));
  89.     }
  90.     
  91.     /**
  92.      * _writeInt
  93.      *
  94.      * @access  private
  95.      * @return  int
  96.      * @param   int     $int
  97.      */
  98.     function _writeInt($int)
  99.     {
  100.         return $this->_write(pack($this->writeBigEndian ? 'N' : 'V', (int) $int));
  101.     }
  102.     
  103.     /**
  104.      * _write
  105.      *
  106.      * @access  private
  107.      * @return  int
  108.      * @param   string  $data
  109.      */
  110.     function _write($data)
  111.     {
  112.         return fwrite($this->_handle, $data);
  113.     }
  114.     
  115.     /**
  116.      * _writeStr
  117.      *
  118.      * @access  private
  119.      * @return  int
  120.      * @param   string  $string
  121.      */
  122.     function _writeStr($string)
  123.     {
  124.         return $this->_write($string . "\0");
  125.     }
  126.     
  127.     /**
  128.      * _readStr
  129.      *
  130.      * @access  private
  131.      * @return  string
  132.      * @param   array   $params     associative array with offset and length 
  133.      *                              of the string
  134.      */
  135.     function _readStr($params)
  136.     {
  137.         fseek($this->_handle, $params['offset']);
  138.         return $this->_read($params['length']);
  139.     }
  140.     
  141.     /**
  142.      * Load MO file
  143.      *
  144.      * @access   public
  145.      * @return   mixed   Returns true on success or PEAR_Error on failure.
  146.      * @param    string  $file
  147.      */
  148.     function load($file = null)
  149.     {
  150.         $this->strings = array();
  151.         
  152.         if (!isset($file)) {
  153.             $file = $this->file;
  154.         }
  155.         
  156.         // open MO file
  157.         if (!is_resource($this->_handle = @fopen($file, 'rb'))) {
  158.             return parent::raiseError($php_errormsg . ' ' . $file);
  159.         }
  160.         // lock MO file shared
  161.         if (!@flock($this->_handle, LOCK_SH)) {
  162.             @fclose($this->_handle);
  163.             return parent::raiseError($php_errormsg . ' ' . $file);
  164.         }
  165.         
  166.         // read (part of) magic number from MO file header and define endianess
  167.         switch ($magic = current($array = unpack('c', $this->_read(4))))
  168.         {
  169.             case -34:
  170.                 $be = false;
  171.             break;
  172.             
  173.             case -107:
  174.                 $be = true;
  175.             break;
  176.             
  177.             default:
  178.                 return parent::raiseError("No GNU mo file: $file (magic: $magic)");
  179.         }
  180.  
  181.         // check file format revision - we currently only support 0
  182.         if (0 !== ($_rev = $this->_readInt($be))) {
  183.             return parent::raiseError('Invalid file format revision: ' . $_rev);
  184.         }
  185.        
  186.         // count of strings in this file
  187.         $count = $this->_readInt($be);
  188.         
  189.         // offset of hashing table of the msgids
  190.         $offset_original = $this->_readInt($be);
  191.         // offset of hashing table of the msgstrs
  192.         $offset_translat = $this->_readInt($be);
  193.         
  194.         // move to msgid hash table
  195.         fseek($this->_handle, $offset_original);
  196.         // read lengths and offsets of msgids
  197.         $original = array();
  198.         for ($i = 0; $i < $count; $i++) {
  199.             $original[$i] = array(
  200.                 'length' => $this->_readInt($be),
  201.                 'offset' => $this->_readInt($be)
  202.             );
  203.         }
  204.         
  205.         // move to msgstr hash table
  206.         fseek($this->_handle, $offset_translat);
  207.         // read lengths and offsets of msgstrs
  208.         $translat = array();
  209.         for ($i = 0; $i < $count; $i++) {
  210.             $translat[$i] = array(
  211.                 'length' => $this->_readInt($be),
  212.                 'offset' => $this->_readInt($be)
  213.             );
  214.         }
  215.         
  216.         // read all
  217.         for ($i = 0; $i < $count; $i++) {
  218.             $this->strings[$this->_readStr($original[$i])] = 
  219.                 $this->_readStr($translat[$i]);
  220.         }
  221.         
  222.         // done
  223.         @flock($this->_handle, LOCK_UN);
  224.         @fclose($this->_handle);
  225.         $this->_handle = null;
  226.         
  227.         // check for meta info
  228.         if (isset($this->strings[''])) {
  229.             $this->meta = parent::meta2array($this->strings['']);
  230.             unset($this->strings['']);
  231.         }
  232.         
  233.         return true;
  234.     }
  235.     
  236.     /**
  237.      * Save MO file
  238.      *
  239.      * @access  public
  240.      * @return  mixed   Returns true on success or PEAR_Error on failure.
  241.      * @param   string  $file
  242.      */
  243.     function save($file = null)
  244.     {
  245.         if (!isset($file)) {
  246.             $file = $this->file;
  247.         }
  248.         
  249.         // open MO file
  250.         if (!is_resource($this->_handle = @fopen($file, 'wb'))) {
  251.             return parent::raiseError($php_errormsg . ' ' . $file);
  252.         }
  253.         // lock MO file exclusively
  254.         if (!@flock($this->_handle, LOCK_EX)) {
  255.             @fclose($this->_handle);
  256.             return parent::raiseError($php_errormsg . ' ' . $file);
  257.         }
  258.         
  259.         // write magic number
  260.         if ($this->writeBigEndian) {
  261.             $this->_write(pack('c*', 0x95, 0x04, 0x12, 0xde));
  262.         } else {
  263.             $this->_write(pack('c*', 0xde, 0x12, 0x04, 0x95));
  264.         }
  265.         
  266.         // write file format revision
  267.         $this->_writeInt(0);
  268.         
  269.         $count = count($this->strings) + ($meta = (count($this->meta) ? 1 : 0));
  270.         // write count of strings
  271.         $this->_writeInt($count);
  272.         
  273.         $offset = 28;
  274.         // write offset of orig. strings hash table
  275.         $this->_writeInt($offset);
  276.         
  277.         $offset += ($count * 8);
  278.         // write offset transl. strings hash table
  279.         $this->_writeInt($offset);
  280.         
  281.         // write size of hash table (we currently ommit the hash table)
  282.         $this->_writeInt(0);
  283.         
  284.         $offset += ($count * 8);
  285.         // write offset of hash table
  286.         $this->_writeInt($offset);
  287.         
  288.         // unshift meta info
  289.         if ($meta) {
  290.             $meta = '';
  291.             foreach ($this->meta as $key => $val) {
  292.                 $meta .= $key . ': ' . $val . "\n";
  293.             }
  294.             $strings = array('' => $meta) + $this->strings;
  295.         } else {
  296.             $strings = $this->strings;
  297.         }
  298.         
  299.         // write offsets for original strings
  300.         foreach (array_keys($strings) as $o) {
  301.             $len = strlen($o);
  302.             $this->_writeInt($len);
  303.             $this->_writeInt($offset);
  304.             $offset += $len + 1;
  305.         }
  306.         
  307.         // write offsets for translated strings
  308.         foreach ($strings as $t) {
  309.             $len = strlen($t);
  310.             $this->_writeInt($len);
  311.             $this->_writeInt($offset);
  312.             $offset += $len + 1;
  313.         }
  314.  
  315.         // write original strings
  316.         foreach (array_keys($strings) as $o) {
  317.             $this->_writeStr($o);
  318.         }
  319.  
  320.         // write translated strings
  321.         foreach ($strings as $t) {
  322.             $this->_writeStr($t);
  323.         }
  324.         
  325.         // done
  326.         @flock($this->_handle, LOCK_UN);
  327.         @fclose($this->_handle);
  328.         return true;
  329.     }
  330. }
  331. ?>
  332.