110 lines
2.8 KiB
PHP
110 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace PhpMyAdmin\MoTranslator;
|
|
|
|
use PhpMyAdmin\MoTranslator\Cache\CacheInterface;
|
|
|
|
use function is_readable;
|
|
use function strcmp;
|
|
|
|
final class MoParser
|
|
{
|
|
/**
|
|
* None error.
|
|
*/
|
|
public const ERROR_NONE = 0;
|
|
/**
|
|
* File does not exist.
|
|
*/
|
|
public const ERROR_DOES_NOT_EXIST = 1;
|
|
/**
|
|
* File has bad magic number.
|
|
*/
|
|
public const ERROR_BAD_MAGIC = 2;
|
|
/**
|
|
* Error while reading file, probably too short.
|
|
*/
|
|
public const ERROR_READING = 3;
|
|
|
|
/**
|
|
* Big endian mo file magic bytes.
|
|
*/
|
|
public const MAGIC_BE = "\x95\x04\x12\xde";
|
|
/**
|
|
* Little endian mo file magic bytes.
|
|
*/
|
|
public const MAGIC_LE = "\xde\x12\x04\x95";
|
|
|
|
/**
|
|
* Parse error code (0 if no error).
|
|
*
|
|
* @var int
|
|
*/
|
|
public $error = self::ERROR_NONE;
|
|
|
|
/** @var string|null */
|
|
private $filename;
|
|
|
|
public function __construct(?string $filename)
|
|
{
|
|
$this->filename = $filename;
|
|
}
|
|
|
|
/**
|
|
* Parses .mo file and stores results to `$cache`
|
|
*/
|
|
public function parseIntoCache(CacheInterface $cache): void
|
|
{
|
|
if ($this->filename === null) {
|
|
return;
|
|
}
|
|
|
|
if (! is_readable($this->filename)) {
|
|
$this->error = self::ERROR_DOES_NOT_EXIST;
|
|
|
|
return;
|
|
}
|
|
|
|
$stream = new StringReader($this->filename);
|
|
|
|
try {
|
|
$magic = $stream->read(0, 4);
|
|
if (strcmp($magic, self::MAGIC_LE) === 0) {
|
|
$unpack = 'V';
|
|
} elseif (strcmp($magic, self::MAGIC_BE) === 0) {
|
|
$unpack = 'N';
|
|
} else {
|
|
$this->error = self::ERROR_BAD_MAGIC;
|
|
|
|
return;
|
|
}
|
|
|
|
/* Parse header */
|
|
$total = $stream->readint($unpack, 8);
|
|
$originals = $stream->readint($unpack, 12);
|
|
$translations = $stream->readint($unpack, 16);
|
|
|
|
/* get original and translations tables */
|
|
$totalTimesTwo = (int) ($total * 2);// Fix for issue #36 on ARM
|
|
$tableOriginals = $stream->readintarray($unpack, $originals, $totalTimesTwo);
|
|
$tableTranslations = $stream->readintarray($unpack, $translations, $totalTimesTwo);
|
|
|
|
/* read all strings to the cache */
|
|
for ($i = 0; $i < $total; ++$i) {
|
|
$iTimesTwo = $i * 2;
|
|
$iPlusOne = $iTimesTwo + 1;
|
|
$iPlusTwo = $iTimesTwo + 2;
|
|
$original = $stream->read($tableOriginals[$iPlusTwo], $tableOriginals[$iPlusOne]);
|
|
$translation = $stream->read($tableTranslations[$iPlusTwo], $tableTranslations[$iPlusOne]);
|
|
$cache->set($original, $translation);
|
|
}
|
|
} catch (ReaderException $e) {
|
|
$this->error = self::ERROR_READING;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|