final move of files
[web.mtrack] / Zend / Search / Lucene / Storage / File / Memory.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) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
20  * @version    $Id: Memory.php 16971 2009-07-22 18:05:45Z mikaelkael $
21  */
22
23 /** Zend_Search_Lucene_Storage_File */
24 require_once 'Zend/Search/Lucene/Storage/File.php';
25
26 /**
27  * @category   Zend
28  * @package    Zend_Search_Lucene
29  * @subpackage Storage
30  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
31  * @license    http://framework.zend.com/license/new-bsd     New BSD License
32  */
33 class Zend_Search_Lucene_Storage_File_Memory extends Zend_Search_Lucene_Storage_File
34 {
35     /**
36      * FileData
37      *
38      * @var string
39      */
40     private $_data;
41
42     /**
43      * File Position
44      *
45      * @var integer
46      */
47     private $_position = 0;
48
49
50     /**
51      * Object constractor
52      *
53      * @param string $data
54      */
55     public function __construct($data)
56     {
57         $this->_data = $data;
58     }
59
60     /**
61      * Reads $length number of bytes at the current position in the
62      * file and advances the file pointer.
63      *
64      * @param integer $length
65      * @return string
66      */
67     protected function _fread($length = 1)
68     {
69         $returnValue = substr($this->_data, $this->_position, $length);
70         $this->_position += $length;
71         return $returnValue;
72     }
73
74
75     /**
76      * Sets the file position indicator and advances the file pointer.
77      * The new position, measured in bytes from the beginning of the file,
78      * is obtained by adding offset to the position specified by whence,
79      * whose values are defined as follows:
80      * SEEK_SET - Set position equal to offset bytes.
81      * SEEK_CUR - Set position to current location plus offset.
82      * SEEK_END - Set position to end-of-file plus offset. (To move to
83      * a position before the end-of-file, you need to pass a negative value
84      * in offset.)
85      * Upon success, returns 0; otherwise, returns -1
86      *
87      * @param integer $offset
88      * @param integer $whence
89      * @return integer
90      */
91     public function seek($offset, $whence=SEEK_SET)
92     {
93         switch ($whence) {
94             case SEEK_SET:
95                 $this->_position = $offset;
96                 break;
97
98             case SEEK_CUR:
99                 $this->_position += $offset;
100                 break;
101
102             case SEEK_END:
103                 $this->_position = strlen($this->_data);
104                 $this->_position += $offset;
105                 break;
106
107             default:
108                 break;
109         }
110     }
111
112     /**
113      * Get file position.
114      *
115      * @return integer
116      */
117     public function tell()
118     {
119         return $this->_position;
120     }
121
122     /**
123      * Flush output.
124      *
125      * Returns true on success or false on failure.
126      *
127      * @return boolean
128      */
129     public function flush()
130     {
131         // Do nothing
132
133         return true;
134     }
135
136     /**
137      * Writes $length number of bytes (all, if $length===null) to the end
138      * of the file.
139      *
140      * @param string $data
141      * @param integer $length
142      */
143     protected function _fwrite($data, $length=null)
144     {
145         // We do not need to check if file position points to the end of "file".
146         // Only append operation is supported now
147
148         if ($length !== null) {
149             $this->_data .= substr($data, 0, $length);
150         } else {
151             $this->_data .= $data;
152         }
153
154         $this->_position = strlen($this->_data);
155     }
156
157     /**
158      * Lock file
159      *
160      * Lock type may be a LOCK_SH (shared lock) or a LOCK_EX (exclusive lock)
161      *
162      * @param integer $lockType
163      * @return boolean
164      */
165     public function lock($lockType, $nonBlockinLock = false)
166     {
167         // Memory files can't be shared
168         // do nothing
169
170         return true;
171     }
172
173     /**
174      * Unlock file
175      */
176     public function unlock()
177     {
178         // Memory files can't be shared
179         // do nothing
180     }
181
182     /**
183      * Reads a byte from the current position in the file
184      * and advances the file pointer.
185      *
186      * @return integer
187      */
188     public function readByte()
189     {
190         return ord($this->_data[$this->_position++]);
191     }
192
193     /**
194      * Writes a byte to the end of the file.
195      *
196      * @param integer $byte
197      */
198     public function writeByte($byte)
199     {
200         // We do not need to check if file position points to the end of "file".
201         // Only append operation is supported now
202
203         $this->_data .= chr($byte);
204         $this->_position = strlen($this->_data);
205
206         return 1;
207     }
208
209     /**
210      * Read num bytes from the current position in the file
211      * and advances the file pointer.
212      *
213      * @param integer $num
214      * @return string
215      */
216     public function readBytes($num)
217     {
218         $returnValue = substr($this->_data, $this->_position, $num);
219         $this->_position += $num;
220
221         return $returnValue;
222     }
223
224     /**
225      * Writes num bytes of data (all, if $num===null) to the end
226      * of the string.
227      *
228      * @param string $data
229      * @param integer $num
230      */
231     public function writeBytes($data, $num=null)
232     {
233         // We do not need to check if file position points to the end of "file".
234         // Only append operation is supported now
235
236         if ($num !== null) {
237             $this->_data .= substr($data, 0, $num);
238         } else {
239             $this->_data .= $data;
240         }
241
242         $this->_position = strlen($this->_data);
243     }
244
245
246     /**
247      * Reads an integer from the current position in the file
248      * and advances the file pointer.
249      *
250      * @return integer
251      */
252     public function readInt()
253     {
254         $str = substr($this->_data, $this->_position, 4);
255         $this->_position += 4;
256
257         return  ord($str[0]) << 24 |
258                 ord($str[1]) << 16 |
259                 ord($str[2]) << 8  |
260                 ord($str[3]);
261     }
262
263
264     /**
265      * Writes an integer to the end of file.
266      *
267      * @param integer $value
268      */
269     public function writeInt($value)
270     {
271         // We do not need to check if file position points to the end of "file".
272         // Only append operation is supported now
273
274         settype($value, 'integer');
275         $this->_data .= chr($value>>24 & 0xFF) .
276                         chr($value>>16 & 0xFF) .
277                         chr($value>>8  & 0xFF) .
278                         chr($value     & 0xFF);
279
280         $this->_position = strlen($this->_data);
281     }
282
283
284     /**
285      * Returns a long integer from the current position in the file
286      * and advances the file pointer.
287      *
288      * @return integer
289      * @throws Zend_Search_Lucene_Exception
290      */
291     public function readLong()
292     {
293         /**
294          * Check, that we work in 64-bit mode.
295          * fseek() uses long for offset. Thus, largest index segment file size in 32bit mode is 2Gb
296          */
297         if (PHP_INT_SIZE > 4) {
298             $str = substr($this->_data, $this->_position, 8);
299             $this->_position += 8;
300
301             return  ord($str[0]) << 56  |
302                     ord($str[1]) << 48  |
303                     ord($str[2]) << 40  |
304                     ord($str[3]) << 32  |
305                     ord($str[4]) << 24  |
306                     ord($str[5]) << 16  |
307                     ord($str[6]) << 8   |
308                     ord($str[7]);
309         } else {
310             return $this->readLong32Bit();
311         }
312     }
313
314     /**
315      * Writes long integer to the end of file
316      *
317      * @param integer $value
318      * @throws Zend_Search_Lucene_Exception
319      */
320     public function writeLong($value)
321     {
322         // We do not need to check if file position points to the end of "file".
323         // Only append operation is supported now
324
325         /**
326          * Check, that we work in 64-bit mode.
327          * fseek() and ftell() use long for offset. Thus, largest index segment file size in 32bit mode is 2Gb
328          */
329         if (PHP_INT_SIZE > 4) {
330             settype($value, 'integer');
331             $this->_data .= chr($value>>56 & 0xFF) .
332                             chr($value>>48 & 0xFF) .
333                             chr($value>>40 & 0xFF) .
334                             chr($value>>32 & 0xFF) .
335                             chr($value>>24 & 0xFF) .
336                             chr($value>>16 & 0xFF) .
337                             chr($value>>8  & 0xFF) .
338                             chr($value     & 0xFF);
339         } else {
340             $this->writeLong32Bit($value);
341         }
342
343         $this->_position = strlen($this->_data);
344     }
345
346
347     /**
348      * Returns a long integer from the current position in the file,
349      * advances the file pointer and return it as float (for 32-bit platforms).
350      *
351      * @return integer|float
352      * @throws Zend_Search_Lucene_Exception
353      */
354     public function readLong32Bit()
355     {
356         $wordHigh = $this->readInt();
357         $wordLow  = $this->readInt();
358
359         if ($wordHigh & (int)0x80000000) {
360             // It's a negative value since the highest bit is set
361             if ($wordHigh == (int)0xFFFFFFFF  &&  ($wordLow & (int)0x80000000)) {
362                 return $wordLow;
363             } else {
364                 require_once 'Zend/Search/Lucene/Exception.php';
365                 throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.');
366             }
367
368         }
369
370         if ($wordLow < 0) {
371             // Value is large than 0x7FFF FFFF. Represent low word as float.
372             $wordLow &= 0x7FFFFFFF;
373             $wordLow += (float)0x80000000;
374         }
375
376         if ($wordHigh == 0) {
377             // Return value as integer if possible
378             return $wordLow;
379         }
380
381         return $wordHigh*(float)0x100000000/* 0x00000001 00000000 */ + $wordLow;
382     }
383
384
385     /**
386      * Writes long integer to the end of file (32-bit platforms implementation)
387      *
388      * @param integer|float $value
389      * @throws Zend_Search_Lucene_Exception
390      */
391     public function writeLong32Bit($value)
392     {
393         if ($value < (int)0x80000000) {
394             require_once 'Zend/Search/Lucene/Exception.php';
395             throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.');
396         }
397
398         if ($value < 0) {
399             $wordHigh = (int)0xFFFFFFFF;
400             $wordLow  = (int)$value;
401         } else {
402             $wordHigh = (int)($value/(float)0x100000000/* 0x00000001 00000000 */);
403             $wordLow  = $value - $wordHigh*(float)0x100000000/* 0x00000001 00000000 */;
404
405             if ($wordLow > 0x7FFFFFFF) {
406                 // Highest bit of low word is set. Translate it to the corresponding negative integer value
407                 $wordLow -= 0x80000000;
408                 $wordLow |= 0x80000000;
409             }
410         }
411
412         $this->writeInt($wordHigh);
413         $this->writeInt($wordLow);
414     }
415
416     /**
417      * Returns a variable-length integer from the current
418      * position in the file and advances the file pointer.
419      *
420      * @return integer
421      */
422     public function readVInt()
423     {
424         $nextByte = ord($this->_data[$this->_position++]);
425         $val = $nextByte & 0x7F;
426
427         for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) {
428             $nextByte = ord($this->_data[$this->_position++]);
429             $val |= ($nextByte & 0x7F) << $shift;
430         }
431         return $val;
432     }
433
434     /**
435      * Writes a variable-length integer to the end of file.
436      *
437      * @param integer $value
438      */
439     public function writeVInt($value)
440     {
441         // We do not need to check if file position points to the end of "file".
442         // Only append operation is supported now
443
444         settype($value, 'integer');
445         while ($value > 0x7F) {
446             $this->_data .= chr( ($value & 0x7F)|0x80 );
447             $value >>= 7;
448         }
449         $this->_data .= chr($value);
450
451         $this->_position = strlen($this->_data);
452     }
453
454
455     /**
456      * Reads a string from the current position in the file
457      * and advances the file pointer.
458      *
459      * @return string
460      */
461     public function readString()
462     {
463         $strlen = $this->readVInt();
464         if ($strlen == 0) {
465             return '';
466         } else {
467             /**
468              * This implementation supports only Basic Multilingual Plane
469              * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
470              * "supplementary characters" (characters whose code points are
471              * greater than 0xFFFF)
472              * Java 2 represents these characters as a pair of char (16-bit)
473              * values, the first from the high-surrogates range (0xD800-0xDBFF),
474              * the second from the low-surrogates range (0xDC00-0xDFFF). Then
475              * they are encoded as usual UTF-8 characters in six bytes.
476              * Standard UTF-8 representation uses four bytes for supplementary
477              * characters.
478              */
479
480             $str_val = substr($this->_data, $this->_position, $strlen);
481             $this->_position += $strlen;
482
483             for ($count = 0; $count < $strlen; $count++ ) {
484                 if (( ord($str_val[$count]) & 0xC0 ) == 0xC0) {
485                     $addBytes = 1;
486                     if (ord($str_val[$count]) & 0x20 ) {
487                         $addBytes++;
488
489                         // Never used. Java2 doesn't encode strings in four bytes
490                         if (ord($str_val[$count]) & 0x10 ) {
491                             $addBytes++;
492                         }
493                     }
494                     $str_val .= substr($this->_data, $this->_position, $addBytes);
495                     $this->_position += $addBytes;
496                     $strlen          += $addBytes;
497
498                     // Check for null character. Java2 encodes null character
499                     // in two bytes.
500                     if (ord($str_val[$count])   == 0xC0 &&
501                         ord($str_val[$count+1]) == 0x80   ) {
502                         $str_val[$count] = 0;
503                         $str_val = substr($str_val,0,$count+1)
504                                  . substr($str_val,$count+2);
505                     }
506                     $count += $addBytes;
507                 }
508             }
509
510             return $str_val;
511         }
512     }
513
514     /**
515      * Writes a string to the end of file.
516      *
517      * @param string $str
518      * @throws Zend_Search_Lucene_Exception
519      */
520     public function writeString($str)
521     {
522         /**
523          * This implementation supports only Basic Multilingual Plane
524          * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
525          * "supplementary characters" (characters whose code points are
526          * greater than 0xFFFF)
527          * Java 2 represents these characters as a pair of char (16-bit)
528          * values, the first from the high-surrogates range (0xD800-0xDBFF),
529          * the second from the low-surrogates range (0xDC00-0xDFFF). Then
530          * they are encoded as usual UTF-8 characters in six bytes.
531          * Standard UTF-8 representation uses four bytes for supplementary
532          * characters.
533          */
534
535         // We do not need to check if file position points to the end of "file".
536         // Only append operation is supported now
537
538         // convert input to a string before iterating string characters
539         settype($str, 'string');
540
541         $chars = $strlen = strlen($str);
542         $containNullChars = false;
543
544         for ($count = 0; $count < $strlen; $count++ ) {
545             /**
546              * String is already in Java 2 representation.
547              * We should only calculate actual string length and replace
548              * \x00 by \xC0\x80
549              */
550             if ((ord($str[$count]) & 0xC0) == 0xC0) {
551                 $addBytes = 1;
552                 if (ord($str[$count]) & 0x20 ) {
553                     $addBytes++;
554
555                     // Never used. Java2 doesn't encode strings in four bytes
556                     // and we dont't support non-BMP characters
557                     if (ord($str[$count]) & 0x10 ) {
558                         $addBytes++;
559                     }
560                 }
561                 $chars -= $addBytes;
562
563                 if (ord($str[$count]) == 0 ) {
564                     $containNullChars = true;
565                 }
566                 $count += $addBytes;
567             }
568         }
569
570         if ($chars < 0) {
571             require_once 'Zend/Search/Lucene/Exception.php';
572             throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string');
573         }
574
575         $this->writeVInt($chars);
576         if ($containNullChars) {
577             $this->_data .= str_replace($str, "\x00", "\xC0\x80");
578
579         } else {
580             $this->_data .= $str;
581         }
582
583         $this->_position = strlen($this->_data);
584     }
585
586
587     /**
588      * Reads binary data from the current position in the file
589      * and advances the file pointer.
590      *
591      * @return string
592      */
593     public function readBinary()
594     {
595         $length = $this->readVInt();
596         $returnValue = substr($this->_data, $this->_position, $length);
597         $this->_position += $length;
598         return $returnValue;
599     }
600 }
601