wp/wp-includes/pomo/mo.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     5  * @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
     5  * @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
     6  * @package pomo
     6  * @package pomo
     7  * @subpackage mo
     7  * @subpackage mo
     8  */
     8  */
     9 
     9 
    10 require_once dirname( __FILE__ ) . '/translations.php';
    10 require_once __DIR__ . '/translations.php';
    11 require_once dirname( __FILE__ ) . '/streams.php';
    11 require_once __DIR__ . '/streams.php';
    12 
    12 
    13 if ( ! class_exists( 'MO', false ) ) :
    13 if ( ! class_exists( 'MO', false ) ) :
    14 	class MO extends Gettext_Translations {
    14 	class MO extends Gettext_Translations {
    15 
    15 
    16 		var $_nplurals = 2;
    16 		var $_nplurals = 2;
    99 		function export_to_file_handle( $fh ) {
    99 		function export_to_file_handle( $fh ) {
   100 			$entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
   100 			$entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
   101 			ksort( $entries );
   101 			ksort( $entries );
   102 			$magic                     = 0x950412de;
   102 			$magic                     = 0x950412de;
   103 			$revision                  = 0;
   103 			$revision                  = 0;
   104 			$total                     = count( $entries ) + 1; // all the headers are one entry
   104 			$total                     = count( $entries ) + 1; // All the headers are one entry.
   105 			$originals_lenghts_addr    = 28;
   105 			$originals_lenghts_addr    = 28;
   106 			$translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
   106 			$translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
   107 			$size_of_hash              = 0;
   107 			$size_of_hash              = 0;
   108 			$hash_addr                 = $translations_lenghts_addr + 8 * $total;
   108 			$hash_addr                 = $translations_lenghts_addr + 8 * $total;
   109 			$current_addr              = $hash_addr;
   109 			$current_addr              = $hash_addr;
   120 					$hash_addr
   120 					$hash_addr
   121 				)
   121 				)
   122 			);
   122 			);
   123 			fseek( $fh, $originals_lenghts_addr );
   123 			fseek( $fh, $originals_lenghts_addr );
   124 
   124 
   125 			// headers' msgid is an empty string
   125 			// Headers' msgid is an empty string.
   126 			fwrite( $fh, pack( 'VV', 0, $current_addr ) );
   126 			fwrite( $fh, pack( 'VV', 0, $current_addr ) );
   127 			$current_addr++;
   127 			$current_addr++;
   128 			$originals_table = "\0";
   128 			$originals_table = "\0";
   129 
   129 
   130 			$reader = new POMO_Reader();
   130 			$reader = new POMO_Reader();
   131 
   131 
   132 			foreach ( $entries as $entry ) {
   132 			foreach ( $entries as $entry ) {
   133 				$originals_table .= $this->export_original( $entry ) . "\0";
   133 				$originals_table .= $this->export_original( $entry ) . "\0";
   134 				$length           = $reader->strlen( $this->export_original( $entry ) );
   134 				$length           = $reader->strlen( $this->export_original( $entry ) );
   135 				fwrite( $fh, pack( 'VV', $length, $current_addr ) );
   135 				fwrite( $fh, pack( 'VV', $length, $current_addr ) );
   136 				$current_addr += $length + 1; // account for the NULL byte after
   136 				$current_addr += $length + 1; // Account for the NULL byte after.
   137 			}
   137 			}
   138 
   138 
   139 			$exported_headers = $this->export_headers();
   139 			$exported_headers = $this->export_headers();
   140 			fwrite( $fh, pack( 'VV', $reader->strlen( $exported_headers ), $current_addr ) );
   140 			fwrite( $fh, pack( 'VV', $reader->strlen( $exported_headers ), $current_addr ) );
   141 			$current_addr      += strlen( $exported_headers ) + 1;
   141 			$current_addr      += strlen( $exported_headers ) + 1;
   156 		/**
   156 		/**
   157 		 * @param Translation_Entry $entry
   157 		 * @param Translation_Entry $entry
   158 		 * @return string
   158 		 * @return string
   159 		 */
   159 		 */
   160 		function export_original( $entry ) {
   160 		function export_original( $entry ) {
   161 			//TODO: warnings for control characters
   161 			// TODO: Warnings for control characters.
   162 			$exported = $entry->singular;
   162 			$exported = $entry->singular;
   163 			if ( $entry->is_plural ) {
   163 			if ( $entry->is_plural ) {
   164 				$exported .= "\0" . $entry->plural;
   164 				$exported .= "\0" . $entry->plural;
   165 			}
   165 			}
   166 			if ( $entry->context ) {
   166 			if ( $entry->context ) {
   172 		/**
   172 		/**
   173 		 * @param Translation_Entry $entry
   173 		 * @param Translation_Entry $entry
   174 		 * @return string
   174 		 * @return string
   175 		 */
   175 		 */
   176 		function export_translations( $entry ) {
   176 		function export_translations( $entry ) {
   177 			//TODO: warnings for control characters
   177 			// TODO: Warnings for control characters.
   178 			return $entry->is_plural ? implode( "\0", $entry->translations ) : $entry->translations[0];
   178 			return $entry->is_plural ? implode( "\0", $entry->translations ) : $entry->translations[0];
   179 		}
   179 		}
   180 
   180 
   181 		/**
   181 		/**
   182 		 * @return string
   182 		 * @return string
   192 		/**
   192 		/**
   193 		 * @param int $magic
   193 		 * @param int $magic
   194 		 * @return string|false
   194 		 * @return string|false
   195 		 */
   195 		 */
   196 		function get_byteorder( $magic ) {
   196 		function get_byteorder( $magic ) {
   197 			// The magic is 0x950412de
   197 			// The magic is 0x950412de.
   198 
   198 
   199 			// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
   199 			// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
   200 			$magic_little    = (int) - 1794895138;
   200 			$magic_little    = (int) - 1794895138;
   201 			$magic_little_64 = (int) 2500072158;
   201 			$magic_little_64 = (int) 2500072158;
   202 			// 0xde120495
   202 			// 0xde120495
   219 			if ( false === $endian_string ) {
   219 			if ( false === $endian_string ) {
   220 				return false;
   220 				return false;
   221 			}
   221 			}
   222 			$reader->setEndian( $endian_string );
   222 			$reader->setEndian( $endian_string );
   223 
   223 
   224 			$endian = ( 'big' == $endian_string ) ? 'N' : 'V';
   224 			$endian = ( 'big' === $endian_string ) ? 'N' : 'V';
   225 
   225 
   226 			$header = $reader->read( 24 );
   226 			$header = $reader->read( 24 );
   227 			if ( $reader->strlen( $header ) != 24 ) {
   227 			if ( $reader->strlen( $header ) != 24 ) {
   228 				return false;
   228 				return false;
   229 			}
   229 			}
   230 
   230 
   231 			// parse header
   231 			// Parse header.
   232 			$header = unpack( "{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header );
   232 			$header = unpack( "{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header );
   233 			if ( ! is_array( $header ) ) {
   233 			if ( ! is_array( $header ) ) {
   234 				return false;
   234 				return false;
   235 			}
   235 			}
   236 
   236 
   237 			// support revision 0 of MO format specs, only
   237 			// Support revision 0 of MO format specs, only.
   238 			if ( $header['revision'] != 0 ) {
   238 			if ( 0 != $header['revision'] ) {
   239 				return false;
   239 				return false;
   240 			}
   240 			}
   241 
   241 
   242 			// seek to data blocks
   242 			// Seek to data blocks.
   243 			$reader->seekto( $header['originals_lenghts_addr'] );
   243 			$reader->seekto( $header['originals_lenghts_addr'] );
   244 
   244 
   245 			// read originals' indices
   245 			// Read originals' indices.
   246 			$originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
   246 			$originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
   247 			if ( $originals_lengths_length != $header['total'] * 8 ) {
   247 			if ( $originals_lengths_length != $header['total'] * 8 ) {
   248 				return false;
   248 				return false;
   249 			}
   249 			}
   250 
   250 
   251 			$originals = $reader->read( $originals_lengths_length );
   251 			$originals = $reader->read( $originals_lengths_length );
   252 			if ( $reader->strlen( $originals ) != $originals_lengths_length ) {
   252 			if ( $reader->strlen( $originals ) != $originals_lengths_length ) {
   253 				return false;
   253 				return false;
   254 			}
   254 			}
   255 
   255 
   256 			// read translations' indices
   256 			// Read translations' indices.
   257 			$translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
   257 			$translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
   258 			if ( $translations_lenghts_length != $header['total'] * 8 ) {
   258 			if ( $translations_lenghts_length != $header['total'] * 8 ) {
   259 				return false;
   259 				return false;
   260 			}
   260 			}
   261 
   261 
   262 			$translations = $reader->read( $translations_lenghts_length );
   262 			$translations = $reader->read( $translations_lenghts_length );
   263 			if ( $reader->strlen( $translations ) != $translations_lenghts_length ) {
   263 			if ( $reader->strlen( $translations ) != $translations_lenghts_length ) {
   264 				return false;
   264 				return false;
   265 			}
   265 			}
   266 
   266 
   267 			// transform raw data into set of indices
   267 			// Transform raw data into set of indices.
   268 			$originals    = $reader->str_split( $originals, 8 );
   268 			$originals    = $reader->str_split( $originals, 8 );
   269 			$translations = $reader->str_split( $translations, 8 );
   269 			$translations = $reader->str_split( $translations, 8 );
   270 
   270 
   271 			// skip hash table
   271 			// Skip hash table.
   272 			$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
   272 			$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
   273 
   273 
   274 			$reader->seekto( $strings_addr );
   274 			$reader->seekto( $strings_addr );
   275 
   275 
   276 			$strings = $reader->read_all();
   276 			$strings = $reader->read_all();
   281 				$t = unpack( "{$endian}length/{$endian}pos", $translations[ $i ] );
   281 				$t = unpack( "{$endian}length/{$endian}pos", $translations[ $i ] );
   282 				if ( ! $o || ! $t ) {
   282 				if ( ! $o || ! $t ) {
   283 					return false;
   283 					return false;
   284 				}
   284 				}
   285 
   285 
   286 				// adjust offset due to reading strings to separate space before
   286 				// Adjust offset due to reading strings to separate space before.
   287 				$o['pos'] -= $strings_addr;
   287 				$o['pos'] -= $strings_addr;
   288 				$t['pos'] -= $strings_addr;
   288 				$t['pos'] -= $strings_addr;
   289 
   289 
   290 				$original    = $reader->substr( $strings, $o['pos'], $o['length'] );
   290 				$original    = $reader->substr( $strings, $o['pos'], $o['length'] );
   291 				$translation = $reader->substr( $strings, $t['pos'], $t['length'] );
   291 				$translation = $reader->substr( $strings, $t['pos'], $t['length'] );
   317 			$parts = explode( "\4", $original );
   317 			$parts = explode( "\4", $original );
   318 			if ( isset( $parts[1] ) ) {
   318 			if ( isset( $parts[1] ) ) {
   319 				$original       = $parts[1];
   319 				$original       = $parts[1];
   320 				$entry->context = $parts[0];
   320 				$entry->context = $parts[0];
   321 			}
   321 			}
   322 			// look for plural original
   322 			// Look for plural original.
   323 			$parts           = explode( "\0", $original );
   323 			$parts           = explode( "\0", $original );
   324 			$entry->singular = $parts[0];
   324 			$entry->singular = $parts[0];
   325 			if ( isset( $parts[1] ) ) {
   325 			if ( isset( $parts[1] ) ) {
   326 				$entry->is_plural = true;
   326 				$entry->is_plural = true;
   327 				$entry->plural    = $parts[1];
   327 				$entry->plural    = $parts[1];
   328 			}
   328 			}
   329 			// plural translations are also separated by \0
   329 			// Plural translations are also separated by \0.
   330 			$entry->translations = explode( "\0", $translation );
   330 			$entry->translations = explode( "\0", $translation );
   331 			return $entry;
   331 			return $entry;
   332 		}
   332 		}
   333 
   333 
   334 		/**
   334 		/**