Вход Регистрация
Файл: framework/i18n/gettext/CGettextMoFile.php
Строк: 275
<?php
/**
 * CGettextMoFile class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright Copyright &copy; 2008-2011 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

/**
 * CGettextMoFile represents an MO Gettext message file.
 *
 * This class is written by adapting Michael's Gettext_MO class in PEAR.
 * Please refer to the following license terms.
 *
 * Copyright (c) 2004-2005, Michael Wallner <mike@iworks.at>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @package system.i18n.gettext
 * @since 1.0
 */
class CGettextMoFile extends CGettextFile
{
    
/**
     * @var boolean whether to use Big Endian when reading and writing an integer.
     */
    
public $useBigEndian=false;

    
/**
     * Constructor.
     * @param boolean $useBigEndian whether to use Big Endian when reading and writing an integer.
     */
    
public function __construct($useBigEndian=false)
    {
        
$this->useBigEndian=$useBigEndian;
    }

    
/**
     * Loads messages from an MO file.
     * @param string $file file path
     * @param string $context message context
     * @return array message translations (source message => translated message)
     */
    
public function load($file,$context)
    {
        if(!(
$fr=@fopen($file,'rb')))
            throw new 
CException(Yii::t('yii','Unable to read file "{file}".',
                array(
'{file}'=>$file)));

        if(!@
flock($fr,LOCK_SH))
            throw new 
CException(Yii::t('yii','Unable to lock file "{file}" for reading.',
                array(
'{file}'=>$file)));

        
$magic=current($array=unpack('c',$this->readByte($fr,4)));
        if(
$magic==-34)
            
$this->useBigEndian=false;
        elseif(
$magic==-107)
            
$this->useBigEndian=true;
        else
            throw new 
CException(Yii::t('yii','Invalid MO file: {file} (magic: {magic}).',
                array(
'{file}'=>$file,'{magic}'=>$magic)));

        if((
$revision=$this->readInteger($fr))!=0)
            throw new 
CException(Yii::t('yii','Invalid MO file revision: {revision}.',
                array(
'{revision}'=>$revision)));

        
$count=$this->readInteger($fr);
        
$sourceOffset=$this->readInteger($fr);
        
$targetOffset=$this->readInteger($fr);

        
$sourceLengths=array();
        
$sourceOffsets=array();
        
fseek($fr,$sourceOffset);
        for(
$i=0;$i<$count;++$i)
        {
            
$sourceLengths[]=$this->readInteger($fr);
            
$sourceOffsets[]=$this->readInteger($fr);
        }

        
$targetLengths=array();
        
$targetOffsets=array();
        
fseek($fr,$targetOffset);
        for(
$i=0;$i<$count;++$i)
        {
            
$targetLengths[]=$this->readInteger($fr);
            
$targetOffsets[]=$this->readInteger($fr);
        }

        
$messages=array();
        for(
$i=0;$i<$count;++$i)
        {
            
$id=$this->readString($fr,$sourceLengths[$i],$sourceOffsets[$i]);
            
$pos strpos($id,chr(4));

            if((
$context && $pos!==false && substr($id,0,$pos)===$context) || (!$context && $pos===false))
            {
                if(
$pos !== false)
                    
$id=substr($id,$pos+1);

                
$message=$this->readString($fr,$targetLengths[$i],$targetOffsets[$i]);
                
$messages[$id]=$message;
            }
        }

        @
flock($fr,LOCK_UN);
        @
fclose($fr);

        return 
$messages;
    }

    
/**
     * Saves messages to an MO file.
     * @param string $file file path
     * @param array $messages message translations (message id => translated message).
     * Note if the message has a context, the message id must be prefixed with
     * the context with chr(4) as the separator.
     */
    
public function save($file,$messages)
    {
        if(!(
$fw=@fopen($file,'wb')))
            throw new 
CException(Yii::t('yii','Unable to write file "{file}".',
                array(
'{file}'=>$file)));

        if(!@
flock($fw,LOCK_EX))
            throw new 
CException(Yii::t('yii','Unable to lock file "{file}" for writing.',
                array(
'{file}'=>$file)));

        
// magic
        
if($this->useBigEndian)
            
$this->writeByte($fw,pack('c*'0x950x040x120xde));
        else
            
$this->writeByte($fw,pack('c*'0xde0x120x040x95));

        
// revision
        
$this->writeInteger($fw,0);

        
// message count
        
$n=count($messages);
        
$this->writeInteger($fw,$n);

        
// offset of source message table
        
$offset=28;
        
$this->writeInteger($fw,$offset);
        
$offset+=($n*8);
        
$this->writeInteger($fw,$offset);
        
// hashtable size, omitted
        
$this->writeInteger($fw,0);
        
$offset+=($n*8);
        
$this->writeInteger($fw,$offset);

        
// length and offsets for source messagess
        
foreach(array_keys($messages) as $id)
        {
            
$len=strlen($id);
            
$this->writeInteger($fw,$len);
            
$this->writeInteger($fw,$offset);
            
$offset+=$len+1;
        }

        
// length and offsets for target messagess
        
foreach($messages as $message)
        {
            
$len=strlen($message);
            
$this->writeInteger($fw,$len);
            
$this->writeInteger($fw,$offset);
            
$offset+=$len+1;
        }

        
// source messages
        
foreach(array_keys($messages) as $id)
            
$this->writeString($fw,$id);

        
// target messages
        
foreach($messages as $message)
            
$this->writeString($fw,$message);

        @
flock($fw,LOCK_UN);
        @
fclose($fw);
    }

    
/**
     * Reads one or several bytes.
     * @param resource $fr file handle
     * @param integer $n number of bytes to read
     * @return string bytes
     */
    
protected function readByte($fr,$n=1)
    {
        if(
$n>0)
            return 
fread($fr,$n);
    }

    
/**
     * Writes bytes.
     * @param resource $fw file handle
     * @param string $data the data
     * @return integer how many bytes are written
     */
    
protected function writeByte($fw,$data)
    {
        return 
fwrite($fw,$data);
    }

    
/**
     * Reads a 4-byte integer.
     * @param resource $fr file handle
     * @return integer the result
     * @see useBigEndian
     */
    
protected function readInteger($fr)
    {
        return 
current($array=unpack($this->useBigEndian 'N' 'V'$this->readByte($fr,4)));
    }

    
/**
     * Writes a 4-byte integer.
     * @param resource $fw file handle
     * @param integer $data the data
     * @return integer how many bytes are written
     */
    
protected function writeInteger($fw,$data)
    {
        return 
$this->writeByte($fw,pack($this->useBigEndian 'N' 'V', (int)$data));
    }

    
/**
     * Reads a string.
     * @param resource $fr file handle
     * @param integer $length string length
     * @param integer $offset offset of the string in the file. If null, it reads from the current position.
     * @return string the result
     */
    
protected function readString($fr,$length,$offset=null)
    {
        if(
$offset!==null)
            
fseek($fr,$offset);
        return 
$this->readByte($fr,$length);
    }

    
/**
     * Writes a string.
     * @param resource $fw file handle
     * @param string $data the string
     * @return integer how many bytes are written
     */
    
protected function writeString($fw,$data)
    {
        return 
$this->writeByte($fw,$data."");
    }
}
Онлайн: 0
Реклама