1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Translation\Dumper;
13
14use Symfony\Component\Translation\MessageCatalogue;
15
16/**
17 * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
18 *
19 * @author Stealth35
20 */
21class IcuResFileDumper extends FileDumper
22{
23    /**
24     * {@inheritdoc}
25     */
26    protected $relativePathTemplate = '%domain%/%locale%.%extension%';
27
28    /**
29     * {@inheritdoc}
30     */
31    public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = [])
32    {
33        $data = $indexes = $resources = '';
34
35        foreach ($messages->all($domain) as $source => $target) {
36            $indexes .= pack('v', \strlen($data) + 28);
37            $data .= $source."\0";
38        }
39
40        $data .= $this->writePadding($data);
41
42        $keyTop = $this->getPosition($data);
43
44        foreach ($messages->all($domain) as $source => $target) {
45            $resources .= pack('V', $this->getPosition($data));
46
47            $data .= pack('V', \strlen($target))
48                .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
49                .$this->writePadding($data)
50                  ;
51        }
52
53        $resOffset = $this->getPosition($data);
54
55        $data .= pack('v', \count($messages->all($domain)))
56            .$indexes
57            .$this->writePadding($data)
58            .$resources
59              ;
60
61        $bundleTop = $this->getPosition($data);
62
63        $root = pack('V7',
64            $resOffset + (2 << 28), // Resource Offset + Resource Type
65            6,                      // Index length
66            $keyTop,                        // Index keys top
67            $bundleTop,                     // Index resources top
68            $bundleTop,                     // Index bundle top
69            \count($messages->all($domain)), // Index max table length
70            0                               // Index attributes
71        );
72
73        $header = pack('vC2v4C12@32',
74            32,                     // Header size
75            0xDA, 0x27,             // Magic number 1 and 2
76            20, 0, 0, 2,            // Rest of the header, ..., Size of a char
77            0x52, 0x65, 0x73, 0x42, // Data format identifier
78            1, 2, 0, 0,             // Data version
79            1, 4, 0, 0              // Unicode version
80        );
81
82        return $header.$root.$data;
83    }
84
85    private function writePadding(string $data): ?string
86    {
87        $padding = \strlen($data) % 4;
88
89        return $padding ? str_repeat("\xAA", 4 - $padding) : null;
90    }
91
92    private function getPosition(string $data)
93    {
94        return (\strlen($data) + 28) / 4;
95    }
96
97    /**
98     * {@inheritdoc}
99     */
100    protected function getExtension()
101    {
102        return 'res';
103    }
104}
105