WordPress.org

Make WordPress Core

Changeset 12174


Ignore:
Timestamp:
11/12/2009 04:05:43 PM (9 years ago)
Author:
ryan
Message:

pomo performance improvements. Props nbachiyski. fixes #10165

Location:
trunk/wp-includes/pomo
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/pomo/mo.php

    r12079 r12174  
    33 * Class for working with MO files
    44 *
    5  * @version $Id: mo.php 221 2009-09-07 21:08:21Z nbachiyski $
     5 * @version $Id: mo.php 293 2009-11-12 15:43:50Z nbachiyski $
    66 * @package pomo
    77 * @subpackage mo
     
    2222     */
    2323    function import_from_file($filename) {
    24         $reader = new POMO_CachedIntFileReader($filename);
    25         if (isset($reader->error)) {
    26             return false;
    27         }
     24        $reader = new POMO_FileReader($filename);
     25        if (!$reader->is_resource())
     26            return false;
    2827        return $this->import_from_reader($reader);
    2928    }
     
    114113
    115114    function import_from_reader($reader) {
    116         $reader->setEndian('little');
    117         $endian = MO::get_byteorder($reader->readint32());
    118         if (false === $endian) {
    119             return false;
    120         }
    121         $reader->setEndian($endian);
    122 
    123         $revision = $reader->readint32();
    124         $total = $reader->readint32();
    125         // get addresses of array of lenghts and offsets for original string and translations
    126         $originals_lenghts_addr = $reader->readint32();
    127         $translations_lenghts_addr = $reader->readint32();
    128 
     115        $endian_string = MO::get_byteorder($reader->readint32());
     116        if (false === $endian_string) {
     117            return false;
     118        }
     119        $reader->setEndian($endian_string);
     120
     121        $endian = ('big' == $endian_string)? 'N' : 'V';
     122
     123        $header = $reader->read(24);
     124        if ($reader->strlen($header) != 24)
     125            return false;
     126
     127        // parse header
     128        $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
     129        if (!is_array($header))
     130            return false;
     131
     132        extract( $header );
     133
     134        // support revision 0 of MO format specs, only
     135        if ($revision != 0)
     136            return false;
     137
     138        // seek to data blocks
    129139        $reader->seekto($originals_lenghts_addr);
    130         $originals_lenghts = $reader->readint32array($total * 2); // each of
    131         $reader->seekto($translations_lenghts_addr);
    132         $translations_lenghts = $reader->readint32array($total * 2);
    133 
    134         $length = create_function('$i', 'return $i * 2 + 1;');
    135         $offset = create_function('$i', 'return $i * 2 + 2;');
    136 
    137         for ($i = 0; $i < $total; ++$i) {
    138             $reader->seekto($originals_lenghts[$offset($i)]);
    139             $original = $reader->read($originals_lenghts[$length($i)]);
    140             $reader->seekto($translations_lenghts[$offset($i)]);
    141             $translation = $reader->read($translations_lenghts[$length($i)]);
    142             if ('' == $original) {
     140
     141        // read originals' indices
     142        $originals_lengths_length = $translations_lenghts_addr - $originals_lenghts_addr;
     143        if ( $originals_lengths_length != $total * 8 )
     144            return false;
     145
     146        $originals = $reader->read($originals_lengths_length);
     147        if ( $reader->strlen( $originals ) != $originals_lengths_length )
     148            return false;
     149
     150        // read translations' indices
     151        $translations_lenghts_length = $hash_addr - $translations_lenghts_addr;
     152        if ( $translations_lenghts_length != $total * 8 )
     153            return false;
     154
     155        $translations = $reader->read($translations_lenghts_length);
     156        if ( $reader->strlen( $translations ) != $translations_lenghts_length )
     157            return false;
     158
     159        // transform raw data into set of indices
     160        $originals    = $reader->str_split( $originals, 8 );
     161        $translations = $reader->str_split( $translations, 8 );
     162
     163        // skip hash table
     164        $strings_addr = $hash_addr + $hash_length * 4;
     165
     166        $reader->seekto($strings_addr);
     167
     168        $strings = $reader->read_all();
     169        $reader->close();
     170
     171        for ( $i = 0; $i < $total; $i++ ) {
     172            $o = unpack( "{$endian}length/{$endian}pos", $originals[$i] );
     173            $t = unpack( "{$endian}length/{$endian}pos", $translations[$i] );
     174            if ( !$o || !$t ) return false;
     175
     176            // adjust offset due to reading strings to separate space before
     177            $o['pos'] -= $strings_addr;
     178            $t['pos'] -= $strings_addr;
     179
     180            $original    = $reader->substr( $strings, $o['pos'], $o['length'] );
     181            $translation = $reader->substr( $strings, $t['pos'], $t['length'] );
     182
     183            if ('' === $original) {
    143184                $this->set_headers($this->make_headers($translation));
    144185            } else {
    145                 $this->add_entry($this->make_entry($original, $translation));
     186                $entry = &$this->make_entry($original, $translation);
     187                $this->entries[$entry->key()] = &$entry;
    146188            }
    147189        }
     
    150192
    151193    /**
     194     * Build a Translation_Entry from original string and translation strings,
     195     * found in a MO file
     196     *
    152197     * @static
     198     * @param string $original original string to translate from MO file. Might contain
     199     *  0x04 as context separator or 0x00 as singular/plural separator
     200     * @param string $translation translation string from MO file. Might contain
     201     *  0x00 as a plural translations separator
    153202     */
    154203    function &make_entry($original, $translation) {
    155         $args = array();
     204        $entry = & new Translation_Entry();
    156205        // look for context
    157206        $parts = explode(chr(4), $original);
    158207        if (isset($parts[1])) {
    159208            $original = $parts[1];
    160             $args['context'] = $parts[0];
     209            $entry->context = $parts[0];
    161210        }
    162211        // look for plural original
    163212        $parts = explode(chr(0), $original);
    164         $args['singular'] = $parts[0];
     213        $entry->singular = $parts[0];
    165214        if (isset($parts[1])) {
    166             $args['plural'] = $parts[1];
     215            $entry->is_plural = true;
     216            $entry->plural = $parts[1];
    167217        }
    168218        // plural translations are also separated by \0
    169         $args['translations'] = explode(chr(0), $translation);
    170         $entry = & new Translation_Entry($args);
     219        $entry->translations = explode(chr(0), $translation);
    171220        return $entry;
    172221    }
     
    179228        return $this->_nplurals;
    180229    }
    181 
    182 
    183230}
    184231endif;
  • trunk/wp-includes/pomo/streams.php

    r12079 r12174  
    44 * Based on the classes from Danilo Segan <danilo@kvota.net>
    55 *
    6  * @version $Id: streams.php 223 2009-09-07 21:20:13Z nbachiyski $
     6 * @version $Id: streams.php 293 2009-11-12 15:43:50Z nbachiyski $
    77 * @package pomo
    88 * @subpackage streams
    99 */
    1010
    11 
    12 if ( !class_exists( 'POMO_StringReader' ) ):
    13 /**
    14  * Provides file-like methods for manipulating a string instead
    15  * of a physical file.
    16  */
    17 class POMO_StringReader {
    18   var $_pos;
    19   var $_str;
    20 
    21     function POMO_StringReader($str = '') {
    22         $this->_str = $str;
     11if ( !class_exists( 'POMO_Reader' ) ):
     12class POMO_Reader {
     13   
     14    var $endian = 'little';
     15    var $_post = '';
     16   
     17    function POMO_Reader() {
     18        $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
    2319        $this->_pos = 0;
    24         $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
    25     }
    26 
    27     function _substr($string, $start, $length) {
    28         if ($this->is_overloaded) {
    29             return mb_substr($string,$start,$length,'ascii');
    30         } else {
    31             return substr($string,$start,$length);
    32         }
    33     }
    34    
    35     function _strlen($string) {
    36         if ($this->is_overloaded) {
    37             return mb_strlen($string,'ascii');
    38         } else {
    39             return strlen($string);
    40         }
    41     }
    42 
    43     function read($bytes) {
    44         $data = $this->_substr($this->_str, $this->_pos, $bytes);
    45         $this->_pos += $bytes;
    46         if ($this->_strlen($this->_str) < $this->_pos) $this->_pos = $this->_strlen($this->_str);
    47         return $data;
    48     }
    49 
    50     function seekto($pos) {
    51         $this->_pos = $pos;
    52         if ($this->_strlen($this->_str) < $this->_pos) $this->_pos = $this->_strlen($this->_str);
    53         return $this->_pos;
    54     }
    55 
    56     function pos() {
    57         return $this->_pos;
    58     }
    59 
    60     function length() {
    61         return $this->_strlen($this->_str);
    62     }
    63 
    64 }
    65 endif;
    66 
    67 if ( !class_exists( 'POMO_CachedFileReader' ) ):
    68 /**
    69  * Reads the contents of the file in the beginning.
    70  */
    71 class POMO_CachedFileReader extends POMO_StringReader {
    72     function POMO_CachedFileReader($filename) {
    73         parent::POMO_StringReader();
    74         $this->_str = file_get_contents($filename);
    75         if (false === $this->_str)
    76             return false;
    77         $this->_pos = 0;
    78     }
    79 }
    80 endif;
    81 
    82 if ( !class_exists( 'POMO_CachedIntFileReader' ) ):
    83 /**
    84  * Allows reading integers from a file.
    85  */
    86 class POMO_CachedIntFileReader extends POMO_CachedFileReader {
    87 
    88     var $endian = 'little';
    89 
    90     /**
    91      * Opens a file and caches it.
    92      *
    93      * @param $filename string name of the file to be opened
    94      * @param $endian string endianness of the words in the file, allowed
    95      *  values are 'little' or 'big'. Default value is 'little'
    96      */
    97     function POMO_CachedIntFileReader($filename, $endian = 'little') {
    98         $this->endian = $endian;
    99         parent::POMO_CachedFileReader($filename);
    100     }
    101 
     20    }
     21   
    10222    /**
    10323     * Sets the endianness of the file.
     
    11737    function readint32() {
    11838        $bytes = $this->read(4);
    119         if (4 != $this->_strlen($bytes))
     39        if (4 != $this->strlen($bytes))
    12040            return false;
    12141        $endian_letter = ('big' == $this->endian)? 'N' : 'V';
     
    13353    function readint32array($count) {
    13454        $bytes = $this->read(4 * $count);
    135         if (4*$count != $this->_strlen($bytes))
     55        if (4*$count != $this->strlen($bytes))
    13656            return false;
    13757        $endian_letter = ('big' == $this->endian)? 'N' : 'V';
    13858        return unpack($endian_letter.$count, $bytes);
    13959    }
    140 }
    141 endif;
     60   
     61   
     62    function substr($string, $start, $length) {
     63        if ($this->is_overloaded) {
     64            return mb_substr($string, $start, $length, 'ascii');
     65        } else {
     66            return substr($string, $start, $length);
     67        }
     68    }
     69   
     70    function strlen($string) {
     71        if ($this->is_overloaded) {
     72            return mb_strlen($string, 'ascii');
     73        } else {
     74            return strlen($string);
     75        }
     76    }
     77   
     78    function str_split($string, $chunk_size) {
     79        if (!function_exists('str_split')) {
     80            $length = $this->strlen($string);
     81            $out = array();
     82            for ($i = 0; $i < $length; $i += $chunk_size)
     83                $out[] = $this->substr($string, $i, $chunk_size);
     84            return $out;
     85        } else {
     86            return str_split( $string, $chunk_size );
     87        }
     88    }
     89   
     90       
     91    function pos() {
     92        return $this->_pos;
     93    }
     94
     95    function is_resource() {
     96        return true;
     97    }
     98   
     99    function close() {
     100        return true;
     101    }
     102}
     103endif;
     104
     105if ( !class_exists( 'POMO_FileReader' ) ):
     106class POMO_FileReader extends POMO_Reader {
     107    function POMO_FileReader($filename) {
     108        parent::POMO_Reader();
     109        $this->_f = fopen($filename, 'r');
     110    }
     111   
     112    function read($bytes) {
     113        return fread($this->_f, $bytes);
     114    }
     115   
     116    function seekto($pos) {
     117        if ( -1 == fseek($this->_f, $pos, SEEK_SET)) {
     118            return false;
     119        }
     120        $this->_pos = $pos;
     121        return true;
     122    }
     123   
     124    function is_resource() {
     125        return is_resource($this->_f);
     126    }
     127   
     128    function feof() {
     129        return feof($this->_f);
     130    }
     131   
     132    function close() {
     133        return fclose($this->_f);
     134    }
     135   
     136    function read_all() {
     137        $all = '';
     138        while ( !$this->feof() )
     139            $all .= $this->read(4096);
     140        return $all;
     141    }
     142}
     143endif;
     144
     145if ( !class_exists( 'POMO_StringReader' ) ):
     146/**
     147 * Provides file-like methods for manipulating a string instead
     148 * of a physical file.
     149 */
     150class POMO_StringReader extends POMO_Reader {
     151   
     152    var $_str = '';
     153   
     154    function POMO_StringReader($str = '') {
     155        parent::POMO_Reader();
     156        $this->_str = $str;
     157        $this->_pos = 0;
     158    }
     159
     160
     161    function read($bytes) {
     162        $data = $this->substr($this->_str, $this->_pos, $bytes);
     163        $this->_pos += $bytes;
     164        if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
     165        return $data;
     166    }
     167
     168    function seekto($pos) {
     169        $this->_pos = $pos;
     170        if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
     171        return $this->_pos;
     172    }
     173
     174    function length() {
     175        return $this->strlen($this->_str);
     176    }
     177
     178    function read_all() {
     179        return $this->substr($this->_str, $this->_pos, $this->strlen($this->_str));
     180    }
     181   
     182}
     183endif;
     184
     185if ( !class_exists( 'POMO_CachedFileReader' ) ):
     186/**
     187 * Reads the contents of the file in the beginning.
     188 */
     189class POMO_CachedFileReader extends POMO_StringReader {
     190    function POMO_CachedFileReader($filename) {
     191        parent::POMO_StringReader();
     192        $this->_str = file_get_contents($filename);
     193        if (false === $this->_str)
     194            return false;
     195        $this->_pos = 0;
     196    }
     197}
     198endif;
     199
     200if ( !class_exists( 'POMO_CachedIntFileReader' ) ):
     201/**
     202 * Reads the contents of the file in the beginning.
     203 */
     204class POMO_CachedIntFileReader extends POMO_CachedFileReader {
     205    function POMO_CachedIntFileReader($filename) {
     206        parent::POMO_CachedFileReader($filename);
     207    }
     208}
     209endif;
Note: See TracChangeset for help on using the changeset viewer.