Initial commit
[moodle.git] / search / Zend / Search / Lucene / Storage / File.php
1 <?php
2 /**
3  * Zend Framework
4  *
5  * LICENSE
6  *
7  * This source file is subject to the new BSD license that is bundled
8  * with this package in the file LICENSE.txt.
9  * It is also available through the world-wide-web at this URL:
10  * http://framework.zend.com/license/new-bsd
11  * If you did not receive a copy of the license and are unable to
12  * obtain it through the world-wide-web, please send an email
13  * to license@zend.com so we can send you a copy immediately.
14  *
15  * @category   Zend
16  * @package    Zend_Search_Lucene
17  * @subpackage Storage
18  * @copyright  Copyright (c) 2006 Zend Technologies USA Inc. (http://www.zend.com)
19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
20  */
23 /**
24  * @category   Zend
25  * @package    Zend_Search_Lucene
26  * @subpackage Storage
27  * @copyright  Copyright (c) 2006 Zend Technologies USA Inc. (http://www.zend.com)
28  * @license    http://framework.zend.com/license/new-bsd     New BSD License
29  */
30 abstract class Zend_Search_Lucene_Storage_File
31 {
32     /**
33      * Reads $length number of bytes at the current position in the
34      * file and advances the file pointer.
35      *
36      * @param integer $length
37      * @return string
38      */
39     abstract protected function _fread($length=1);
42     /**
43      * Sets the file position indicator and advances the file pointer.
44      * The new position, measured in bytes from the beginning of the file,
45      * is obtained by adding offset to the position specified by whence,
46      * whose values are defined as follows:
47      * SEEK_SET - Set position equal to offset bytes.
48      * SEEK_CUR - Set position to current location plus offset.
49      * SEEK_END - Set position to end-of-file plus offset. (To move to
50      * a position before the end-of-file, you need to pass a negative value
51      * in offset.)
52      * Upon success, returns 0; otherwise, returns -1
53      *
54      * @param integer $offset
55      * @param integer $whence
56      * @return integer
57      */
58     abstract public function seek($offset, $whence=SEEK_SET);
60     /**
61      * Get file position.
62      *
63      * @return integer
64      */
65     abstract public function tell();
67     /**
68      * Writes $length number of bytes (all, if $length===null) to the end
69      * of the file.
70      *
71      * @param string $data
72      * @param integer $length
73      */
74     abstract protected function _fwrite($data, $length=null);
77     /**
78      * Reads a byte from the current position in the file
79      * and advances the file pointer.
80      *
81      * @return integer
82      */
83     public function readByte()
84     {
85         return ord($this->_fread(1));
86     }
88     /**
89      * Writes a byte to the end of the file.
90      *
91      * @param integer $byte
92      */
93     public function writeByte($byte)
94     {
95         return $this->_fwrite(chr($byte), 1);
96     }
98     /**
99      * Read num bytes from the current position in the file
100      * and advances the file pointer.
101      *
102      * @param integer $num
103      * @return string
104      */
105     public function readBytes($num)
106     {
107         return $this->_fread($num);
108     }
110     /**
111      * Writes num bytes of data (all, if $num===null) to the end
112      * of the string.
113      *
114      * @param string $data
115      * @param integer $num
116      */
117     public function writeBytes($data, $num=null)
118     {
119         $this->_fwrite($data, $num);
120     }
123     /**
124      * Reads an integer from the current position in the file
125      * and advances the file pointer.
126      *
127      * @return integer
128      */
129     public function readInt()
130     {
131         $str = $this->_fread(4);
133         return  ord($str{0}) << 24 |
134                 ord($str{1}) << 16 |
135                 ord($str{2}) << 8  |
136                 ord($str{3});
137     }
140     /**
141      * Writes an integer to the end of file.
142      *
143      * @param integer $value
144      */
145     public function writeInt($value)
146     {
147         settype($value, 'integer');
148         $this->_fwrite( chr($value>>24 & 0xFF) .
149                         chr($value>>16 & 0xFF) .
150                         chr($value>>8  & 0xFF) .
151                         chr($value     & 0xFF),   4  );
152     }
155     /**
156      * Returns a long integer from the current position in the file
157      * and advances the file pointer.
158      *
159      * @return integer
160      */
161     public function readLong()
162     {
163         $str = $this->_fread(8);
165         /**
166          * PHP uses long as largest integer. fseek() uses long for offset.
167          * long has 4 bytes in a lot of systems. 4 bytes are discarded to prevent
168          * conversion to float.
169          * So, largest index segment file is 2Gb
170          */
171         return  /* ord($str{0}) << 56  | */
172                 /* ord($str{1}) << 48  | */
173                 /* ord($str{2}) << 40  | */
174                 /* ord($str{3}) << 32  | */
175                 ord($str{4}) << 24  |
176                 ord($str{5}) << 16  |
177                 ord($str{6}) << 8   |
178                 ord($str{7});
179     }
181     /**
182      * Writes long integer to the end of file
183      *
184      * @param integer $value
185      */
186     public function writeLong($value)
187     {
188         /**
189          * PHP uses long as largest integer. fseek() uses long for offset.
190          * long has 4 bytes in a lot of systems. 4 bytes are discarded to prevent
191          * conversion to float.
192          * So, largest index segment file is 2Gb
193          */
194         settype($value, 'integer');
195         $this->_fwrite( "\x00\x00\x00\x00"     .
196                         chr($value>>24 & 0xFF) .
197                         chr($value>>16 & 0xFF) .
198                         chr($value>>8  & 0xFF) .
199                         chr($value     & 0xFF),   8  );
200     }
204     /**
205      * Returns a variable-length integer from the current
206      * position in the file and advances the file pointer.
207      *
208      * @return integer
209      */
210     public function readVInt()
211     {
212         $nextByte = ord($this->_fread(1));
213         $val = $nextByte & 0x7F;
215         for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) {
216             $nextByte = ord($this->_fread(1));
217             $val |= ($nextByte & 0x7F) << $shift;
218         }
219         return $val;
220     }
222     /**
223      * Writes a variable-length integer to the end of file.
224      *
225      * @param integer $value
226      */
227     public function writeVInt($value)
228     {
229         settype($value, 'integer');
230         while ($value > 0x7F) {
231             $this->_fwrite(chr( ($value & 0x7F)|0x80 ));
232             $value >>= 7;
233         }
234         $this->_fwrite(chr($value));
235     }
238     /**
239      * Reads a string from the current position in the file
240      * and advances the file pointer.
241      *
242      * @return string
243      */
244     public function readString()
245     {
246         $strlen = $this->readVInt();
247         if ($strlen == 0) {
248             return '';
249         } else {
250             /**
251              * This implementation supports only Basic Multilingual Plane
252              * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
253              * "supplementary characters" (characters whose code points are
254              * greater than 0xFFFF)
255              * Java 2 represents these characters as a pair of char (16-bit)
256              * values, the first from the high-surrogates range (0xD800-0xDBFF),
257              * the second from the low-surrogates range (0xDC00-0xDFFF). Then
258              * they are encoded as usual UTF-8 characters in six bytes.
259              * Standard UTF-8 representation uses four bytes for supplementary
260              * characters.
261              */
263             $str_val = $this->_fread($strlen);
265             for ($count = 0; $count < $strlen; $count++ ) {
266                 if (( ord($str_val{$count}) & 0xC0 ) == 0xC0) {
267                     $addBytes = 1;
268                     if (ord($str_val{$count}) & 0x20 ) {
269                         $addBytes++;
271                         // Never used. Java2 doesn't encode strings in four bytes
272                         if (ord($str_val{$count}) & 0x10 ) {
273                             $addBytes++;
274                         }
275                     }
276                     $str_val .= $this->_fread($addBytes);
277                     $strlen += $addBytes;
279                     // Check for null character. Java2 encodes null character
280                     // in two bytes.
281                     if (ord($str_val{$count})   == 0xC0 &&
282                         ord($str_val{$count+1}) == 0x80   ) {
283                         $str_val{$count} = 0;
284                         $str_val = substr($str_val,0,$count+1)
285                                  . substr($str_val,$count+2);
286                     }
287                     $count += $addBytes;
288                 }
289             }
291             return $str_val;
292         }
293     }
295     /**
296      * Writes a string to the end of file.
297      *
298      * @param string $str
299      * @throws Zend_Search_Lucene_Exception
300      */
301     public function writeString($str)
302     {
303         /**
304          * This implementation supports only Basic Multilingual Plane
305          * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
306          * "supplementary characters" (characters whose code points are
307          * greater than 0xFFFF)
308          * Java 2 represents these characters as a pair of char (16-bit)
309          * values, the first from the high-surrogates range (0xD800-0xDBFF),
310          * the second from the low-surrogates range (0xDC00-0xDFFF). Then
311          * they are encoded as usual UTF-8 characters in six bytes.
312          * Standard UTF-8 representation uses four bytes for supplementary
313          * characters.
314          */
316         // convert input to a string before iterating string characters
317         settype($str, 'string');
319         $chars = $strlen = strlen($str);
320         $containNullChars = false;
322         for ($count = 0; $count < $strlen; $count++ ) {
323             /**
324              * String is already in Java 2 representation.
325              * We should only calculate actual string length and replace
326              * \x00 by \xC0\x80
327              */
328             if ((ord($str{$count}) & 0xC0) == 0xC0) {
329                 $addBytes = 1;
330                 if (ord($str{$count}) & 0x20 ) {
331                     $addBytes++;
333                     // Never used. Java2 doesn't encode strings in four bytes
334                     // and we dont't support non-BMP characters
335                     if (ord($str{$count}) & 0x10 ) {
336                         $addBytes++;
337                     }
338                 }
339                 $chars -= $addBytes;
341                 if (ord($str{$count}) == 0 ) {
342                     $containNullChars = true;
343                 }
344                 $count += $addBytes;
345             }
346         }
348         if ($chars < 0) {
349             throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string');
350         }
352         $this->writeVInt($chars);
353         if ($containNullChars) {
354             $this->_fwrite(str_replace($str, "\x00", "\xC0\x80"));
355         } else {
356             $this->_fwrite($str);
357         }
358     }
361     /**
362      * Reads binary data from the current position in the file
363      * and advances the file pointer.
364      *
365      * @return string
366      */
367     public function readBinary()
368     {
369         return $this->_fread($this->readVInt());
370     }