annotate vendor/symfony/translation/Loader/MoFileLoader.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Translation\Loader;
Chris@0 13
Chris@0 14 use Symfony\Component\Translation\Exception\InvalidResourceException;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
Chris@0 18 */
Chris@0 19 class MoFileLoader extends FileLoader
Chris@0 20 {
Chris@0 21 /**
Chris@0 22 * Magic used for validating the format of a MO file as well as
Chris@0 23 * detecting if the machine used to create that file was little endian.
Chris@0 24 *
Chris@0 25 * @var float
Chris@0 26 */
Chris@0 27 const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
Chris@0 28
Chris@0 29 /**
Chris@0 30 * Magic used for validating the format of a MO file as well as
Chris@0 31 * detecting if the machine used to create that file was big endian.
Chris@0 32 *
Chris@0 33 * @var float
Chris@0 34 */
Chris@0 35 const MO_BIG_ENDIAN_MAGIC = 0xde120495;
Chris@0 36
Chris@0 37 /**
Chris@0 38 * The size of the header of a MO file in bytes.
Chris@0 39 *
Chris@0 40 * @var int Number of bytes
Chris@0 41 */
Chris@0 42 const MO_HEADER_SIZE = 28;
Chris@0 43
Chris@0 44 /**
Chris@0 45 * Parses machine object (MO) format, independent of the machine's endian it
Chris@0 46 * was created on. Both 32bit and 64bit systems are supported.
Chris@0 47 *
Chris@0 48 * {@inheritdoc}
Chris@0 49 */
Chris@0 50 protected function loadResource($resource)
Chris@0 51 {
Chris@0 52 $stream = fopen($resource, 'r');
Chris@0 53
Chris@0 54 $stat = fstat($stream);
Chris@0 55
Chris@0 56 if ($stat['size'] < self::MO_HEADER_SIZE) {
Chris@0 57 throw new InvalidResourceException('MO stream content has an invalid format.');
Chris@0 58 }
Chris@0 59 $magic = unpack('V1', fread($stream, 4));
Chris@0 60 $magic = hexdec(substr(dechex(current($magic)), -8));
Chris@0 61
Chris@0 62 if ($magic == self::MO_LITTLE_ENDIAN_MAGIC) {
Chris@0 63 $isBigEndian = false;
Chris@0 64 } elseif ($magic == self::MO_BIG_ENDIAN_MAGIC) {
Chris@0 65 $isBigEndian = true;
Chris@0 66 } else {
Chris@0 67 throw new InvalidResourceException('MO stream content has an invalid format.');
Chris@0 68 }
Chris@0 69
Chris@0 70 // formatRevision
Chris@0 71 $this->readLong($stream, $isBigEndian);
Chris@0 72 $count = $this->readLong($stream, $isBigEndian);
Chris@0 73 $offsetId = $this->readLong($stream, $isBigEndian);
Chris@0 74 $offsetTranslated = $this->readLong($stream, $isBigEndian);
Chris@0 75 // sizeHashes
Chris@0 76 $this->readLong($stream, $isBigEndian);
Chris@0 77 // offsetHashes
Chris@0 78 $this->readLong($stream, $isBigEndian);
Chris@0 79
Chris@0 80 $messages = array();
Chris@0 81
Chris@0 82 for ($i = 0; $i < $count; ++$i) {
Chris@0 83 $pluralId = null;
Chris@0 84 $translated = null;
Chris@0 85
Chris@0 86 fseek($stream, $offsetId + $i * 8);
Chris@0 87
Chris@0 88 $length = $this->readLong($stream, $isBigEndian);
Chris@0 89 $offset = $this->readLong($stream, $isBigEndian);
Chris@0 90
Chris@0 91 if ($length < 1) {
Chris@0 92 continue;
Chris@0 93 }
Chris@0 94
Chris@0 95 fseek($stream, $offset);
Chris@0 96 $singularId = fread($stream, $length);
Chris@0 97
Chris@0 98 if (strpos($singularId, "\000") !== false) {
Chris@0 99 list($singularId, $pluralId) = explode("\000", $singularId);
Chris@0 100 }
Chris@0 101
Chris@0 102 fseek($stream, $offsetTranslated + $i * 8);
Chris@0 103 $length = $this->readLong($stream, $isBigEndian);
Chris@0 104 $offset = $this->readLong($stream, $isBigEndian);
Chris@0 105
Chris@0 106 if ($length < 1) {
Chris@0 107 continue;
Chris@0 108 }
Chris@0 109
Chris@0 110 fseek($stream, $offset);
Chris@0 111 $translated = fread($stream, $length);
Chris@0 112
Chris@0 113 if (strpos($translated, "\000") !== false) {
Chris@0 114 $translated = explode("\000", $translated);
Chris@0 115 }
Chris@0 116
Chris@0 117 $ids = array('singular' => $singularId, 'plural' => $pluralId);
Chris@0 118 $item = compact('ids', 'translated');
Chris@0 119
Chris@0 120 if (is_array($item['translated'])) {
Chris@0 121 $messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
Chris@0 122 if (isset($item['ids']['plural'])) {
Chris@0 123 $plurals = array();
Chris@0 124 foreach ($item['translated'] as $plural => $translated) {
Chris@0 125 $plurals[] = sprintf('{%d} %s', $plural, $translated);
Chris@0 126 }
Chris@0 127 $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
Chris@0 128 }
Chris@0 129 } elseif (!empty($item['ids']['singular'])) {
Chris@0 130 $messages[$item['ids']['singular']] = stripcslashes($item['translated']);
Chris@0 131 }
Chris@0 132 }
Chris@0 133
Chris@0 134 fclose($stream);
Chris@0 135
Chris@0 136 return array_filter($messages);
Chris@0 137 }
Chris@0 138
Chris@0 139 /**
Chris@0 140 * Reads an unsigned long from stream respecting endianness.
Chris@0 141 *
Chris@0 142 * @param resource $stream
Chris@0 143 * @param bool $isBigEndian
Chris@0 144 *
Chris@0 145 * @return int
Chris@0 146 */
Chris@0 147 private function readLong($stream, $isBigEndian)
Chris@0 148 {
Chris@0 149 $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
Chris@0 150 $result = current($result);
Chris@0 151
Chris@0 152 return (int) substr($result, -8);
Chris@0 153 }
Chris@0 154 }