- $reader->setEndian($endian);
-
- $revision = $reader->readint32();
- $total = $reader->readint32();
- // get addresses of array of lenghts and offsets for original string and translations
- $originals_lo_addr = $reader->readint32();
- $translations_lo_addr = $reader->readint32();
-
- $reader->seekto($originals_lo_addr);
- $originals_lo = $reader->readint32array($total * 2); // each of
- $reader->seekto($translations_lo_addr);
- $translations_lo = $reader->readint32array($total * 2);
-
- $length = create_function('$i', 'return $i * 2 + 1;');
- $offset = create_function('$i', 'return $i * 2 + 2;');
-
- for ($i = 0; $i < $total; ++$i) {
- $reader->seekto($originals_lo[$offset($i)]);
- $original = $reader->read($originals_lo[$length($i)]);
- $reader->seekto($translations_lo[$offset($i)]);
- $translation = $reader->read($translations_lo[$length($i)]);
- if ('' == $original) {
+ $reader->setEndian($endian_string);
+
+ $endian = ('big' == $endian_string)? 'N' : 'V';
+
+ $header = $reader->read(24);
+ if ($reader->strlen($header) != 24)
+ return false;
+
+ // parse header
+ $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
+ if (!is_array($header))
+ return false;
+
+ // support revision 0 of MO format specs, only
+ if ( $header['revision'] != 0 ) {
+ return false;
+ }
+
+ // seek to data blocks
+ $reader->seekto( $header['originals_lenghts_addr'] );
+
+ // read originals' indices
+ $originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
+ if ( $originals_lengths_length != $header['total'] * 8 ) {
+ return false;
+ }
+
+ $originals = $reader->read($originals_lengths_length);
+ if ( $reader->strlen( $originals ) != $originals_lengths_length ) {
+ return false;
+ }
+
+ // read translations' indices
+ $translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
+ if ( $translations_lenghts_length != $header['total'] * 8 ) {
+ return false;
+ }
+
+ $translations = $reader->read($translations_lenghts_length);
+ if ( $reader->strlen( $translations ) != $translations_lenghts_length ) {
+ return false;
+ }
+
+ // transform raw data into set of indices
+ $originals = $reader->str_split( $originals, 8 );
+ $translations = $reader->str_split( $translations, 8 );
+
+ // skip hash table
+ $strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
+
+ $reader->seekto($strings_addr);
+
+ $strings = $reader->read_all();
+ $reader->close();
+
+ for ( $i = 0; $i < $header['total']; $i++ ) {
+ $o = unpack( "{$endian}length/{$endian}pos", $originals[$i] );
+ $t = unpack( "{$endian}length/{$endian}pos", $translations[$i] );
+ if ( !$o || !$t ) return false;
+
+ // adjust offset due to reading strings to separate space before
+ $o['pos'] -= $strings_addr;
+ $t['pos'] -= $strings_addr;
+
+ $original = $reader->substr( $strings, $o['pos'], $o['length'] );
+ $translation = $reader->substr( $strings, $t['pos'], $t['length'] );
+
+ if ('' === $original) {