Mo   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 4

Importance

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

3 Methods

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