Make WordPress Core

Changeset 12174


Ignore:
Timestamp:
11/12/2009 04:05:43 PM (17 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.