source: trunk/www.guidonia.net/wp/wp-includes/pomo/mo.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 5.2 KB
Line 
1<?php
2/**
3 * Class for working with MO files
4 *
5 * @version $Id: mo.php 106 2009-04-23 19:48:22Z nbachiyski $
6 * @package pomo
7 * @subpackage mo
8 */
9
10require_once dirname(__FILE__) . '/translations.php';
11require_once dirname(__FILE__) . '/streams.php';
12
13class MO extends Gettext_Translations {
14
15 var $_nplurals = 2;
16
17 /**
18 * Fills up with the entries from MO file $filename
19 *
20 * @param string $filename MO file to load
21 */
22 function import_from_file($filename) {
23 $reader = new POMO_CachedIntFileReader($filename);
24 if (isset($reader->error)) {
25 return false;
26 }
27 return $this->import_from_reader($reader);
28 }
29
30 function export_to_file($filename) {
31 $fh = fopen($filename, 'wb');
32 if ( !$fh ) return false;
33 $entries = array_filter($this->entries, create_function('$e', 'return !empty($e->translations);'));
34 ksort($entries);
35 $magic = 0x950412de;
36 $revision = 0;
37 $total = count($entries) + 1; // all the headers are one entry
38 $originals_lenghts_addr = 28;
39 $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
40 $size_of_hash = 0;
41 $hash_addr = $translations_lenghts_addr + 8 * $total;
42 $current_addr = $hash_addr;
43 fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr,
44 $translations_lenghts_addr, $size_of_hash, $hash_addr));
45 fseek($fh, $originals_lenghts_addr);
46
47 // headers' msgid is an empty string
48 fwrite($fh, pack('VV', 0, $current_addr));
49 $current_addr++;
50 $originals_table = chr(0);
51
52 foreach($entries as $entry) {
53 $originals_table .= $this->export_original($entry) . chr(0);
54 $length = strlen($this->export_original($entry));
55 fwrite($fh, pack('VV', $length, $current_addr));
56 $current_addr += $length + 1; // account for the NULL byte after
57 }
58
59 $exported_headers = $this->export_headers();
60 fwrite($fh, pack('VV', strlen($exported_headers), $current_addr));
61 $current_addr += strlen($exported_headers) + 1;
62 $translations_table = $exported_headers . chr(0);
63
64 foreach($entries as $entry) {
65 $translations_table .= $this->export_translations($entry) . chr(0);
66 $length = strlen($this->export_translations($entry));
67 fwrite($fh, pack('VV', $length, $current_addr));
68 $current_addr += $length + 1;
69 }
70
71 fwrite($fh, $originals_table);
72 fwrite($fh, $translations_table);
73 fclose($fh);
74 }
75
76 function export_original($entry) {
77 //TODO: warnings for control characters
78 $exported = $entry->singular;
79 if ($entry->is_plural) $exported .= chr(0).$entry->plural;
80 if (!is_null($entry->context)) $exported = $entry->context . chr(4) . $exported;
81 return $exported;
82 }
83
84 function export_translations($entry) {
85 //TODO: warnings for control characters
86 return implode(chr(0), $entry->translations);
87 }
88
89 function export_headers() {
90 $exported = '';
91 foreach($this->headers as $header => $value) {
92 $exported.= "$header: $value\n";
93 }
94 return $exported;
95 }
96
97 function get_byteorder($magic) {
98
99 // The magic is 0x950412de
100
101 // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
102 $magic_little = (int) - 1794895138;
103 $magic_little_64 = (int) 2500072158;
104 // 0xde120495
105 $magic_big = ((int) - 569244523) && 0xFFFFFFFF;
106
107 if ($magic_little == $magic || $magic_little_64 == $magic) {
108 return 'little';
109 } else if ($magic_big == $magic) {
110 return 'big';
111 } else {
112 return false;
113 }
114 }
115
116 function import_from_reader($reader) {
117 $reader->setEndian('little');
118 $endian = MO::get_byteorder($reader->readint32());
119 if (false === $endian) {
120 return false;
121 }
122 $reader->setEndian($endian);
123
124 $revision = $reader->readint32();
125 $total = $reader->readint32();
126 // get addresses of array of lenghts and offsets for original string and translations
127 $originals_lenghts_addr = $reader->readint32();
128 $translations_lenghts_addr = $reader->readint32();
129
130 $reader->seekto($originals_lenghts_addr);
131 $originals_lenghts = $reader->readint32array($total * 2); // each of
132 $reader->seekto($translations_lenghts_addr);
133 $translations_lenghts = $reader->readint32array($total * 2);
134
135 $length = create_function('$i', 'return $i * 2 + 1;');
136 $offset = create_function('$i', 'return $i * 2 + 2;');
137
138 for ($i = 0; $i < $total; ++$i) {
139 $reader->seekto($originals_lenghts[$offset($i)]);
140 $original = $reader->read($originals_lenghts[$length($i)]);
141 $reader->seekto($translations_lenghts[$offset($i)]);
142 $translation = $reader->read($translations_lenghts[$length($i)]);
143 if ('' == $original) {
144 $this->set_headers($this->make_headers($translation));
145 } else {
146 $this->add_entry($this->make_entry($original, $translation));
147 }
148 }
149 return true;
150 }
151
152 /**
153 * @static
154 */
155 function &make_entry($original, $translation) {
156 $args = array();
157 // look for context
158 $parts = explode(chr(4), $original);
159 if (isset($parts[1])) {
160 $original = $parts[1];
161 $args['context'] = $parts[0];
162 }
163 // look for plural original
164 $parts = explode(chr(0), $original);
165 $args['singular'] = $parts[0];
166 if (isset($parts[1])) {
167 $args['plural'] = $parts[1];
168 }
169 // plural translations are also separated by \0
170 $args['translations'] = explode(chr(0), $translation);
171 $entry = & new Translation_Entry($args);
172 return $entry;
173 }
174
175 function select_plural_form($count) {
176 return $this->gettext_select_plural_form($count);
177 }
178
179 function get_plural_forms_count() {
180 return $this->_nplurals;
181 }
182
183
184}
185?>
Note: See TracBrowser for help on using the repository browser.