Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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