Mo   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 120
rs 10
c 0
b 0
f 0
wmc 16
lcom 1
cbo 4

3 Methods

Rating   Name   Duplication   Size   Complexity  
C fromString() 0 83 13
A readInt() 0 10 2
A readIntArray() 0 4 1
1
<?php
2
3
namespace Gettext\Extractors;
4
5
use Exception;
6
use Gettext\Translations;
7
use Gettext\Utils\StringReader;
8
9
/**
10
 * Class to get gettext strings from .mo files.
11
 */
12
class Mo extends Extractor implements ExtractorInterface
13
{
14
    const MAGIC1 = -1794895138;
15
    const MAGIC2 = -569244523;
16
    const MAGIC3 = 2500072158;
17
18
    protected static $stringReaderClass = 'Gettext\Utils\StringReader';
19
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public static function fromString($string, Translations $translations, array $options = [])
24
    {
25
        /** @var StringReader $stream */
26
        $stream = new static::$stringReaderClass($string);
27
        $magic = static::readInt($stream, 'V');
28
29
        if (($magic === static::MAGIC1) || ($magic === static::MAGIC3)) { //to make sure it works for 64-bit platforms
30
            $byteOrder = 'V'; //low endian
31
        } elseif ($magic === (static::MAGIC2 & 0xFFFFFFFF)) {
32
            $byteOrder = 'N'; //big endian
33
        } else {
34
            throw new Exception('Not MO file');
35
        }
36
37
        static::readInt($stream, $byteOrder);
38
39
        $total = static::readInt($stream, $byteOrder); //total string count
40
        $originals = static::readInt($stream, $byteOrder); //offset of original table
41
        $tran = static::readInt($stream, $byteOrder); //offset of translation table
42
43
        $stream->seekto($originals);
44
        $table_originals = static::readIntArray($stream, $byteOrder, $total * 2);
45
46
        $stream->seekto($tran);
47
        $table_translations = static::readIntArray($stream, $byteOrder, $total * 2);
48
49
        for ($i = 0; $i < $total; ++$i) {
50
            $next = $i * 2;
51
52
            $stream->seekto($table_originals[$next + 2]);
53
            $original = $stream->read($table_originals[$next + 1]);
54
55
            $stream->seekto($table_translations[$next + 2]);
56
            $translated = $stream->read($table_translations[$next + 1]);
57
58
            if ($original === '') {
59
                // Headers
60
                foreach (explode("\n", $translated) as $headerLine) {
61
                    if ($headerLine === '') {
62
                        continue;
63
                    }
64
65
                    $headerChunks = preg_split('/:\s*/', $headerLine, 2);
66
                    $translations->setHeader($headerChunks[0], isset($headerChunks[1]) ? $headerChunks[1] : '');
67
                }
68
69
                continue;
70
            }
71
72
            $chunks = explode("\x04", $original, 2);
73
74
            if (isset($chunks[1])) {
75
                $context = $chunks[0];
76
                $original = $chunks[1];
77
            } else {
78
                $context = '';
79
            }
80
81
            $chunks = explode("\x00", $original, 2);
82
83
            if (isset($chunks[1])) {
84
                $original = $chunks[0];
85
                $plural = $chunks[1];
86
            } else {
87
                $plural = '';
88
            }
89
90
            $translation = $translations->insert($context, $original, $plural);
91
92
            if ($translated === '') {
93
                continue;
94
            }
95
96
            if ($plural === '') {
97
                $translation->setTranslation($translated);
98
                continue;
99
            }
100
101
            $v = explode("\x00", $translated);
102
            $translation->setTranslation(array_shift($v));
103
            $translation->setPluralTranslations($v);
104
        }
105
    }
106
107
    /**
108
     * @param StringReader $stream
109
     * @param string       $byteOrder
110
     */
111
    protected static function readInt(StringReader $stream, $byteOrder)
112
    {
113
        if (($read = $stream->read(4)) === false) {
114
            return false;
115
        }
116
117
        $read = unpack($byteOrder, $read);
118
119
        return array_shift($read);
120
    }
121
122
    /**
123
     * @param StringReader $stream
124
     * @param string       $byteOrder
125
     * @param int          $count
126
     */
127
    protected static function readIntArray(StringReader $stream, $byteOrder, $count)
128
    {
129
        return unpack($byteOrder.$count, $stream->read(4 * $count));
130
    }
131
}
132