Passed
Push — master ( 122983...91227d )
by William
02:34 queued 26s
created

MoParser::parseIntoCache()   B

Complexity

Conditions 7
Paths 25

Size

Total Lines 49
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 31
c 1
b 0
f 0
nc 25
nop 1
dl 0
loc 49
ccs 30
cts 30
cp 1
crap 7
rs 8.4906
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\MoTranslator;
6
7
use PhpMyAdmin\MoTranslator\Cache\CacheInterface;
8
9
use function is_readable;
10
use function strcmp;
11
12
final class MoParser
13
{
14
    /**
15
     * None error.
16
     */
17
    public const ERROR_NONE = 0;
18
    /**
19
     * File does not exist.
20
     */
21
    public const ERROR_DOES_NOT_EXIST = 1;
22
    /**
23
     * File has bad magic number.
24
     */
25
    public const ERROR_BAD_MAGIC = 2;
26
    /**
27
     * Error while reading file, probably too short.
28
     */
29
    public const ERROR_READING = 3;
30
31
    /**
32
     * Big endian mo file magic bytes.
33
     */
34
    public const MAGIC_BE = "\x95\x04\x12\xde";
35
    /**
36
     * Little endian mo file magic bytes.
37
     */
38
    public const MAGIC_LE = "\xde\x12\x04\x95";
39
40
    /**
41
     * Parse error code (0 if no error).
42
     *
43
     * @var int
44
     */
45
    public $error = self::ERROR_NONE;
46
47
    /** @var string|null */
48
    private $filename;
49
50 234
    public function __construct(?string $filename)
51
    {
52 234
        $this->filename = $filename;
53 59
    }
54
55
    /**
56
     * Parses .mo file and stores results to `$cache`
57
     */
58 228
    public function parseIntoCache(CacheInterface $cache): void
59
    {
60 228
        if ($this->filename === null) {
61 8
            return;
62
        }
63
64 224
        if (! is_readable($this->filename)) {
65 64
            $this->error = self::ERROR_DOES_NOT_EXIST;
66
67 64
            return;
68
        }
69
70 160
        $stream = new StringReader($this->filename);
71
72
        try {
73 160
            $magic = $stream->read(0, 4);
74 156
            if (strcmp($magic, self::MAGIC_LE) === 0) {
75 124
                $unpack = 'V';
76 32
            } elseif (strcmp($magic, self::MAGIC_BE) === 0) {
77 28
                $unpack = 'N';
78
            } else {
79 4
                $this->error = self::ERROR_BAD_MAGIC;
80
81 4
                return;
82
            }
83
84
            /* Parse header */
85 152
            $total = $stream->readint($unpack, 8);
86 152
            $originals = $stream->readint($unpack, 12);
87 140
            $translations = $stream->readint($unpack, 16);
88
89
            /* get original and translations tables */
90 140
            $totalTimesTwo = (int) ($total * 2);// Fix for issue #36 on ARM
91 140
            $tableOriginals = $stream->readintarray($unpack, $originals, $totalTimesTwo);
92 136
            $tableTranslations = $stream->readintarray($unpack, $translations, $totalTimesTwo);
93
94
            /* read all strings to the cache */
95 136
            for ($i = 0; $i < $total; ++$i) {
96 136
                $iTimesTwo = $i * 2;
97 136
                $iPlusOne = $iTimesTwo + 1;
98 136
                $iPlusTwo = $iTimesTwo + 2;
99 136
                $original = $stream->read($tableOriginals[$iPlusTwo], $tableOriginals[$iPlusOne]);
100 136
                $translation = $stream->read($tableTranslations[$iPlusTwo], $tableTranslations[$iPlusOne]);
101 136
                $cache->set($original, $translation);
102
            }
103 20
        } catch (ReaderException $e) {
104 20
            $this->error = self::ERROR_READING;
105
106 20
            return;
107
        }
108 34
    }
109
}
110