Completed
Push — master ( b4ed61...4cdb8c )
by Fabio
15s
created

TGettext_MO::_writeStr()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
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:[email protected] 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
// | [email protected] so we can mail you a copy immediately.               |
28
// +----------------------------------------------------------------------+
29
// | Copyright (c) 2004 Michael Wallner <[email protected]>                  |
30
// +----------------------------------------------------------------------+
31
//
32
// $Id: MO.php 3187 2012-07-12 11:21:01Z ctrlaltca $
33
34
/**
35
 * File::Gettext::MO
36
 *
37
 * @author      Michael Wallner <[email protected]>
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 <[email protected]>
49
 * @version     $Revision: 1.3 $
50
 * @access      public
51
 * @package System.I18N.core
52
 */
53
class TGettext_MO extends TGettext
0 ignored issues
show
Coding Style introduced by
This class is not in CamelCase format.

Classes in PHP are usually named in CamelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. The whole name starts with a capital letter as well.

Thus the name database provider becomes DatabaseProvider.

Loading history...
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
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
78
     * @param   string      $file   path to GNU MO file
79
     */
80
    function __construct($file = '')
81
    {
82
        $this->file = $file;
83
    }
84
85
    /**
86
     * _read
87
     *
88
     * @access  private
89
     * @return  mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
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.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use boolean.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
169
     * @param    string  $file
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
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))
0 ignored issues
show
Unused Code introduced by
$magic is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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.
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use boolean.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
265
     * @param   string  $file
0 ignored issues
show
Documentation introduced by
Should the type for parameter $file not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->meta of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
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
}
356