Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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