Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
// +----------------------------------------------------------------------+
4
// | PEAR :: File :: Gettext :: MO                                        |
5
// +----------------------------------------------------------------------+
6
// | This source file is subject to version 3.0 of the PHP license,       |
7
// | that is available at http://www.php.net/license/3_0.txt              |
8
// | If you did not receive a copy of the PHP license and are unable      |
9
// | to obtain it through the world-wide-web, please send a note to       |
10
// | license@php.net so we can mail you a copy immediately.               |
11
// +----------------------------------------------------------------------+
12
// | Copyright (c) 2004 Michael Wallner <mike@iworks.at>                  |
13
// +----------------------------------------------------------------------+
14
//
15
// $Id: MO.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
16
 
17
/**
18
 * File::Gettext::MO
19
 *
20
 * @author      Michael Wallner <mike@php.net>
21
 * @license     PHP License
22
 */
23
 
24
require_once dirname(__FILE__).'/TGettext.class.php';
25
 
26
/**
27
 * File_Gettext_MO
28
 *
29
 * GNU MO file reader and writer.
30
 *
31
 * @author      Michael Wallner <mike@php.net>
32
 * @version     $Revision: 9856 $
33
 * @access      public
34
 * @package System.I18N.core
35
 */
36
class TGettext_MO extends TGettext
37
{
38
    /**
39
     * file handle
40
     *
41
     * @access  private
42
     * @var     resource
43
     */
44
    protected $_handle = null;
45
 
46
    /**
47
     * big endianess
48
     *
49
     * Whether to write with big endian byte order.
50
     *
51
     * @access  public
52
     * @var     bool
53
     */
54
    protected $writeBigEndian = false;
55
 
56
    /**
57
     * Constructor
58
     *
59
     * @access  public
60
     * @return  object      File_Gettext_MO
61
     * @param   string      $file   path to GNU MO file
62
     */
63
    function TGettext_MO($file = '')
64
    {
65
        $this->file = $file;
66
    }
67
 
68
    /**
69
     * _read
70
     *
71
     * @access  private
72
     * @return  mixed
73
     * @param   int     $bytes
74
     */
75
    function _read($bytes = 1)
76
    {
77
        if (0 < $bytes = abs($bytes)) {
78
            return fread($this->_handle, $bytes);
79
        }
80
        return null;
81
    }
82
 
83
    /**
84
     * _readInt
85
     *
86
     * @access  private
87
     * @return  int
88
     * @param   bool    $bigendian
89
     */
90
    function _readInt($bigendian = false)
91
    {
92
		//unpack returns a reference????
93
		$unpacked = unpack($bigendian ? 'N' : 'V', $this->_read(4));
94
        return array_shift($unpacked);
95
    }
96
 
97
    /**
98
     * _writeInt
99
     *
100
     * @access  private
101
     * @return  int
102
     * @param   int     $int
103
     */
104
    function _writeInt($int)
105
    {
106
        return $this->_write(pack($this->writeBigEndian ? 'N' : 'V', (int) $int));
107
    }
108
 
109
    /**
110
     * _write
111
     *
112
     * @access  private
113
     * @return  int
114
     * @param   string  $data
115
     */
116
    function _write($data)
117
    {
118
        return fwrite($this->_handle, $data);
119
    }
120
 
121
    /**
122
     * _writeStr
123
     *
124
     * @access  private
125
     * @return  int
126
     * @param   string  $string
127
     */
128
    function _writeStr($string)
129
    {
130
        return $this->_write($string . "\0");
131
    }
132
 
133
    /**
134
     * _readStr
135
     *
136
     * @access  private
137
     * @return  string
138
     * @param   array   $params     associative array with offset and length
139
     *                              of the string
140
     */
141
    function _readStr($params)
142
    {
143
        fseek($this->_handle, $params['offset']);
144
        return $this->_read($params['length']);
145
    }
146
 
147
    /**
148
     * Load MO file
149
     *
150
     * @access   public
151
     * @return   mixed   Returns true on success or PEAR_Error on failure.
152
     * @param    string  $file
153
     */
154
    function load($file = null)
155
    {
156
        if (!isset($file)) {
157
            $file = $this->file;
158
        }
159
 
160
        // open MO file
161
        if (!is_resource($this->_handle = @fopen($file, 'rb'))) {
162
            return false;
163
        }
164
        // lock MO file shared
165
        if (!@flock($this->_handle, LOCK_SH)) {
166
            @fclose($this->_handle);
167
            return false;
168
        }
169
 
170
        // read (part of) magic number from MO file header and define endianess
171
 
172
		//unpack returns a reference????
173
		$unpacked = unpack('c', $this->_read(4));
174
        switch ($magic = array_shift($unpacked))
175
        {
176
            case -34:
177
                $be = false;
178
            break;
179
 
180
            case -107:
181
                $be = true;
182
            break;
183
 
184
            default:
185
                return false;
186
        }
187
 
188
        // check file format revision - we currently only support 0
189
        if (0 !== ($_rev = $this->_readInt($be))) {
190
            return false;
191
        }
192
 
193
        // count of strings in this file
194
        $count = $this->_readInt($be);
195
 
196
        // offset of hashing table of the msgids
197
        $offset_original = $this->_readInt($be);
198
        // offset of hashing table of the msgstrs
199
        $offset_translat = $this->_readInt($be);
200
 
201
        // move to msgid hash table
202
        fseek($this->_handle, $offset_original);
203
        // read lengths and offsets of msgids
204
        $original = array();
205
        for ($i = 0; $i < $count; $i++) {
206
            $original[$i] = array(
207
                'length' => $this->_readInt($be),
208
                'offset' => $this->_readInt($be)
209
            );
210
        }
211
 
212
        // move to msgstr hash table
213
        fseek($this->_handle, $offset_translat);
214
        // read lengths and offsets of msgstrs
215
        $translat = array();
216
        for ($i = 0; $i < $count; $i++) {
217
            $translat[$i] = array(
218
                'length' => $this->_readInt($be),
219
                'offset' => $this->_readInt($be)
220
            );
221
        }
222
 
223
        // read all
224
        for ($i = 0; $i < $count; $i++) {
225
            $this->strings[$this->_readStr($original[$i])] =
226
                $this->_readStr($translat[$i]);
227
        }
228
 
229
        // done
230
        @flock($this->_handle, LOCK_UN);
231
        @fclose($this->_handle);
232
        $this->_handle = null;
233
 
234
        // check for meta info
235
        if (isset($this->strings[''])) {
236
            $this->meta = parent::meta2array($this->strings['']);
237
            unset($this->strings['']);
238
        }
239
 
240
        return true;
241
    }
242
 
243
    /**
244
     * Save MO file
245
     *
246
     * @access  public
247
     * @return  mixed   Returns true on success or PEAR_Error on failure.
248
     * @param   string  $file
249
     */
250
    function save($file = null)
251
    {
252
        if (!isset($file)) {
253
            $file = $this->file;
254
        }
255
 
256
        // open MO file
257
        if (!is_resource($this->_handle = @fopen($file, 'wb'))) {
258
            return false;
259
        }
260
        // lock MO file exclusively
261
        if (!@flock($this->_handle, LOCK_EX)) {
262
            @fclose($this->_handle);
263
            return false;
264
        }
265
 
266
        // write magic number
267
        if ($this->writeBigEndian) {
268
            $this->_write(pack('c*', 0x95, 0x04, 0x12, 0xde));
269
        } else {
270
            $this->_write(pack('c*', 0xde, 0x12, 0x04, 0x95));
271
        }
272
 
273
        // write file format revision
274
        $this->_writeInt(0);
275
 
276
        $count = count($this->strings) + ($meta = (count($this->meta) ? 1 : 0));
277
        // write count of strings
278
        $this->_writeInt($count);
279
 
280
        $offset = 28;
281
        // write offset of orig. strings hash table
282
        $this->_writeInt($offset);
283
 
284
        $offset += ($count * 8);
285
        // write offset transl. strings hash table
286
        $this->_writeInt($offset);
287
 
288
        // write size of hash table (we currently ommit the hash table)
289
        $this->_writeInt(0);
290
 
291
        $offset += ($count * 8);
292
        // write offset of hash table
293
        $this->_writeInt($offset);
294
 
295
        // unshift meta info
296
        if ($meta) {
297
            $meta = '';
298
            foreach ($this->meta as $key => $val) {
299
                $meta .= $key . ': ' . $val . "\n";
300
            }
301
            $strings = array('' => $meta) + $this->strings;
302
        } else {
303
            $strings = $this->strings;
304
        }
305
 
306
        // write offsets for original strings
307
        foreach (array_keys($strings) as $o) {
308
            $len = strlen($o);
309
            $this->_writeInt($len);
310
            $this->_writeInt($offset);
311
            $offset += $len + 1;
312
        }
313
 
314
        // write offsets for translated strings
315
        foreach ($strings as $t) {
316
            $len = strlen($t);
317
            $this->_writeInt($len);
318
            $this->_writeInt($offset);
319
            $offset += $len + 1;
320
        }
321
 
322
        // write original strings
323
        foreach (array_keys($strings) as $o) {
324
            $this->_writeStr($o);
325
        }
326
 
327
        // write translated strings
328
        foreach ($strings as $t) {
329
            $this->_writeStr($t);
330
        }
331
 
332
        // done
333
        @flock($this->_handle, LOCK_UN);
334
        @fclose($this->_handle);
335
        return true;
336
    }
337
}