annotate vendor/symfony/translation/Loader/MoFileLoader.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
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 const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
Chris@0 26
Chris@0 27 /**
Chris@0 28 * Magic used for validating the format of a MO file as well as
Chris@0 29 * detecting if the machine used to create that file was big endian.
Chris@0 30 */
Chris@0 31 const MO_BIG_ENDIAN_MAGIC = 0xde120495;
Chris@0 32
Chris@0 33 /**
Chris@0 34 * The size of the header of a MO file in bytes.
Chris@0 35 */
Chris@0 36 const MO_HEADER_SIZE = 28;
Chris@0 37
Chris@0 38 /**
Chris@0 39 * Parses machine object (MO) format, independent of the machine's endian it
Chris@0 40 * was created on. Both 32bit and 64bit systems are supported.
Chris@0 41 *
Chris@0 42 * {@inheritdoc}
Chris@0 43 */
Chris@0 44 protected function loadResource($resource)
Chris@0 45 {
Chris@0 46 $stream = fopen($resource, 'r');
Chris@0 47
Chris@0 48 $stat = fstat($stream);
Chris@0 49
Chris@0 50 if ($stat['size'] < self::MO_HEADER_SIZE) {
Chris@0 51 throw new InvalidResourceException('MO stream content has an invalid format.');
Chris@0 52 }
Chris@0 53 $magic = unpack('V1', fread($stream, 4));
Chris@0 54 $magic = hexdec(substr(dechex(current($magic)), -8));
Chris@0 55
Chris@14 56 if (self::MO_LITTLE_ENDIAN_MAGIC == $magic) {
Chris@0 57 $isBigEndian = false;
Chris@14 58 } elseif (self::MO_BIG_ENDIAN_MAGIC == $magic) {
Chris@0 59 $isBigEndian = true;
Chris@0 60 } else {
Chris@0 61 throw new InvalidResourceException('MO stream content has an invalid format.');
Chris@0 62 }
Chris@0 63
Chris@0 64 // formatRevision
Chris@0 65 $this->readLong($stream, $isBigEndian);
Chris@0 66 $count = $this->readLong($stream, $isBigEndian);
Chris@0 67 $offsetId = $this->readLong($stream, $isBigEndian);
Chris@0 68 $offsetTranslated = $this->readLong($stream, $isBigEndian);
Chris@0 69 // sizeHashes
Chris@0 70 $this->readLong($stream, $isBigEndian);
Chris@0 71 // offsetHashes
Chris@0 72 $this->readLong($stream, $isBigEndian);
Chris@0 73
Chris@17 74 $messages = [];
Chris@0 75
Chris@0 76 for ($i = 0; $i < $count; ++$i) {
Chris@0 77 $pluralId = null;
Chris@0 78 $translated = null;
Chris@0 79
Chris@0 80 fseek($stream, $offsetId + $i * 8);
Chris@0 81
Chris@0 82 $length = $this->readLong($stream, $isBigEndian);
Chris@0 83 $offset = $this->readLong($stream, $isBigEndian);
Chris@0 84
Chris@0 85 if ($length < 1) {
Chris@0 86 continue;
Chris@0 87 }
Chris@0 88
Chris@0 89 fseek($stream, $offset);
Chris@0 90 $singularId = fread($stream, $length);
Chris@0 91
Chris@14 92 if (false !== strpos($singularId, "\000")) {
Chris@0 93 list($singularId, $pluralId) = explode("\000", $singularId);
Chris@0 94 }
Chris@0 95
Chris@0 96 fseek($stream, $offsetTranslated + $i * 8);
Chris@0 97 $length = $this->readLong($stream, $isBigEndian);
Chris@0 98 $offset = $this->readLong($stream, $isBigEndian);
Chris@0 99
Chris@0 100 if ($length < 1) {
Chris@0 101 continue;
Chris@0 102 }
Chris@0 103
Chris@0 104 fseek($stream, $offset);
Chris@0 105 $translated = fread($stream, $length);
Chris@0 106
Chris@14 107 if (false !== strpos($translated, "\000")) {
Chris@0 108 $translated = explode("\000", $translated);
Chris@0 109 }
Chris@0 110
Chris@17 111 $ids = ['singular' => $singularId, 'plural' => $pluralId];
Chris@0 112 $item = compact('ids', 'translated');
Chris@0 113
Chris@17 114 if (\is_array($item['translated'])) {
Chris@0 115 $messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
Chris@0 116 if (isset($item['ids']['plural'])) {
Chris@17 117 $plurals = [];
Chris@0 118 foreach ($item['translated'] as $plural => $translated) {
Chris@0 119 $plurals[] = sprintf('{%d} %s', $plural, $translated);
Chris@0 120 }
Chris@0 121 $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
Chris@0 122 }
Chris@0 123 } elseif (!empty($item['ids']['singular'])) {
Chris@0 124 $messages[$item['ids']['singular']] = stripcslashes($item['translated']);
Chris@0 125 }
Chris@0 126 }
Chris@0 127
Chris@0 128 fclose($stream);
Chris@0 129
Chris@0 130 return array_filter($messages);
Chris@0 131 }
Chris@0 132
Chris@0 133 /**
Chris@0 134 * Reads an unsigned long from stream respecting endianness.
Chris@0 135 *
Chris@0 136 * @param resource $stream
Chris@0 137 * @param bool $isBigEndian
Chris@0 138 *
Chris@0 139 * @return int
Chris@0 140 */
Chris@0 141 private function readLong($stream, $isBigEndian)
Chris@0 142 {
Chris@0 143 $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
Chris@0 144 $result = current($result);
Chris@0 145
Chris@0 146 return (int) substr($result, -8);
Chris@0 147 }
Chris@0 148 }