--- /dev/null
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Search_Lucene
+ * @subpackage Storage
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id: Memory.php 16971 2009-07-22 18:05:45Z mikaelkael $
+ */
+
+/** Zend_Search_Lucene_Storage_File */
+require_once 'Zend/Search/Lucene/Storage/File.php';
+
+/**
+ * @category Zend
+ * @package Zend_Search_Lucene
+ * @subpackage Storage
+ * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Search_Lucene_Storage_File_Memory extends Zend_Search_Lucene_Storage_File
+{
+ /**
+ * FileData
+ *
+ * @var string
+ */
+ private $_data;
+
+ /**
+ * File Position
+ *
+ * @var integer
+ */
+ private $_position = 0;
+
+
+ /**
+ * Object constractor
+ *
+ * @param string $data
+ */
+ public function __construct($data)
+ {
+ $this->_data = $data;
+ }
+
+ /**
+ * Reads $length number of bytes at the current position in the
+ * file and advances the file pointer.
+ *
+ * @param integer $length
+ * @return string
+ */
+ protected function _fread($length = 1)
+ {
+ $returnValue = substr($this->_data, $this->_position, $length);
+ $this->_position += $length;
+ return $returnValue;
+ }
+
+
+ /**
+ * Sets the file position indicator and advances the file pointer.
+ * The new position, measured in bytes from the beginning of the file,
+ * is obtained by adding offset to the position specified by whence,
+ * whose values are defined as follows:
+ * SEEK_SET - Set position equal to offset bytes.
+ * SEEK_CUR - Set position to current location plus offset.
+ * SEEK_END - Set position to end-of-file plus offset. (To move to
+ * a position before the end-of-file, you need to pass a negative value
+ * in offset.)
+ * Upon success, returns 0; otherwise, returns -1
+ *
+ * @param integer $offset
+ * @param integer $whence
+ * @return integer
+ */
+ public function seek($offset, $whence=SEEK_SET)
+ {
+ switch ($whence) {
+ case SEEK_SET:
+ $this->_position = $offset;
+ break;
+
+ case SEEK_CUR:
+ $this->_position += $offset;
+ break;
+
+ case SEEK_END:
+ $this->_position = strlen($this->_data);
+ $this->_position += $offset;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Get file position.
+ *
+ * @return integer
+ */
+ public function tell()
+ {
+ return $this->_position;
+ }
+
+ /**
+ * Flush output.
+ *
+ * Returns true on success or false on failure.
+ *
+ * @return boolean
+ */
+ public function flush()
+ {
+ // Do nothing
+
+ return true;
+ }
+
+ /**
+ * Writes $length number of bytes (all, if $length===null) to the end
+ * of the file.
+ *
+ * @param string $data
+ * @param integer $length
+ */
+ protected function _fwrite($data, $length=null)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ if ($length !== null) {
+ $this->_data .= substr($data, 0, $length);
+ } else {
+ $this->_data .= $data;
+ }
+
+ $this->_position = strlen($this->_data);
+ }
+
+ /**
+ * Lock file
+ *
+ * Lock type may be a LOCK_SH (shared lock) or a LOCK_EX (exclusive lock)
+ *
+ * @param integer $lockType
+ * @return boolean
+ */
+ public function lock($lockType, $nonBlockinLock = false)
+ {
+ // Memory files can't be shared
+ // do nothing
+
+ return true;
+ }
+
+ /**
+ * Unlock file
+ */
+ public function unlock()
+ {
+ // Memory files can't be shared
+ // do nothing
+ }
+
+ /**
+ * Reads a byte from the current position in the file
+ * and advances the file pointer.
+ *
+ * @return integer
+ */
+ public function readByte()
+ {
+ return ord($this->_data[$this->_position++]);
+ }
+
+ /**
+ * Writes a byte to the end of the file.
+ *
+ * @param integer $byte
+ */
+ public function writeByte($byte)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ $this->_data .= chr($byte);
+ $this->_position = strlen($this->_data);
+
+ return 1;
+ }
+
+ /**
+ * Read num bytes from the current position in the file
+ * and advances the file pointer.
+ *
+ * @param integer $num
+ * @return string
+ */
+ public function readBytes($num)
+ {
+ $returnValue = substr($this->_data, $this->_position, $num);
+ $this->_position += $num;
+
+ return $returnValue;
+ }
+
+ /**
+ * Writes num bytes of data (all, if $num===null) to the end
+ * of the string.
+ *
+ * @param string $data
+ * @param integer $num
+ */
+ public function writeBytes($data, $num=null)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ if ($num !== null) {
+ $this->_data .= substr($data, 0, $num);
+ } else {
+ $this->_data .= $data;
+ }
+
+ $this->_position = strlen($this->_data);
+ }
+
+
+ /**
+ * Reads an integer from the current position in the file
+ * and advances the file pointer.
+ *
+ * @return integer
+ */
+ public function readInt()
+ {
+ $str = substr($this->_data, $this->_position, 4);
+ $this->_position += 4;
+
+ return ord($str[0]) << 24 |
+ ord($str[1]) << 16 |
+ ord($str[2]) << 8 |
+ ord($str[3]);
+ }
+
+
+ /**
+ * Writes an integer to the end of file.
+ *
+ * @param integer $value
+ */
+ public function writeInt($value)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ settype($value, 'integer');
+ $this->_data .= chr($value>>24 & 0xFF) .
+ chr($value>>16 & 0xFF) .
+ chr($value>>8 & 0xFF) .
+ chr($value & 0xFF);
+
+ $this->_position = strlen($this->_data);
+ }
+
+
+ /**
+ * Returns a long integer from the current position in the file
+ * and advances the file pointer.
+ *
+ * @return integer
+ * @throws Zend_Search_Lucene_Exception
+ */
+ public function readLong()
+ {
+ /**
+ * Check, that we work in 64-bit mode.
+ * fseek() uses long for offset. Thus, largest index segment file size in 32bit mode is 2Gb
+ */
+ if (PHP_INT_SIZE > 4) {
+ $str = substr($this->_data, $this->_position, 8);
+ $this->_position += 8;
+
+ return ord($str[0]) << 56 |
+ ord($str[1]) << 48 |
+ ord($str[2]) << 40 |
+ ord($str[3]) << 32 |
+ ord($str[4]) << 24 |
+ ord($str[5]) << 16 |
+ ord($str[6]) << 8 |
+ ord($str[7]);
+ } else {
+ return $this->readLong32Bit();
+ }
+ }
+
+ /**
+ * Writes long integer to the end of file
+ *
+ * @param integer $value
+ * @throws Zend_Search_Lucene_Exception
+ */
+ public function writeLong($value)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ /**
+ * Check, that we work in 64-bit mode.
+ * fseek() and ftell() use long for offset. Thus, largest index segment file size in 32bit mode is 2Gb
+ */
+ if (PHP_INT_SIZE > 4) {
+ settype($value, 'integer');
+ $this->_data .= chr($value>>56 & 0xFF) .
+ chr($value>>48 & 0xFF) .
+ chr($value>>40 & 0xFF) .
+ chr($value>>32 & 0xFF) .
+ chr($value>>24 & 0xFF) .
+ chr($value>>16 & 0xFF) .
+ chr($value>>8 & 0xFF) .
+ chr($value & 0xFF);
+ } else {
+ $this->writeLong32Bit($value);
+ }
+
+ $this->_position = strlen($this->_data);
+ }
+
+
+ /**
+ * Returns a long integer from the current position in the file,
+ * advances the file pointer and return it as float (for 32-bit platforms).
+ *
+ * @return integer|float
+ * @throws Zend_Search_Lucene_Exception
+ */
+ public function readLong32Bit()
+ {
+ $wordHigh = $this->readInt();
+ $wordLow = $this->readInt();
+
+ if ($wordHigh & (int)0x80000000) {
+ // It's a negative value since the highest bit is set
+ if ($wordHigh == (int)0xFFFFFFFF && ($wordLow & (int)0x80000000)) {
+ return $wordLow;
+ } else {
+ require_once 'Zend/Search/Lucene/Exception.php';
+ throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.');
+ }
+
+ }
+
+ if ($wordLow < 0) {
+ // Value is large than 0x7FFF FFFF. Represent low word as float.
+ $wordLow &= 0x7FFFFFFF;
+ $wordLow += (float)0x80000000;
+ }
+
+ if ($wordHigh == 0) {
+ // Return value as integer if possible
+ return $wordLow;
+ }
+
+ return $wordHigh*(float)0x100000000/* 0x00000001 00000000 */ + $wordLow;
+ }
+
+
+ /**
+ * Writes long integer to the end of file (32-bit platforms implementation)
+ *
+ * @param integer|float $value
+ * @throws Zend_Search_Lucene_Exception
+ */
+ public function writeLong32Bit($value)
+ {
+ if ($value < (int)0x80000000) {
+ require_once 'Zend/Search/Lucene/Exception.php';
+ throw new Zend_Search_Lucene_Exception('Long integers lower than -2147483648 (0x80000000) are not supported on 32-bit platforms.');
+ }
+
+ if ($value < 0) {
+ $wordHigh = (int)0xFFFFFFFF;
+ $wordLow = (int)$value;
+ } else {
+ $wordHigh = (int)($value/(float)0x100000000/* 0x00000001 00000000 */);
+ $wordLow = $value - $wordHigh*(float)0x100000000/* 0x00000001 00000000 */;
+
+ if ($wordLow > 0x7FFFFFFF) {
+ // Highest bit of low word is set. Translate it to the corresponding negative integer value
+ $wordLow -= 0x80000000;
+ $wordLow |= 0x80000000;
+ }
+ }
+
+ $this->writeInt($wordHigh);
+ $this->writeInt($wordLow);
+ }
+
+ /**
+ * Returns a variable-length integer from the current
+ * position in the file and advances the file pointer.
+ *
+ * @return integer
+ */
+ public function readVInt()
+ {
+ $nextByte = ord($this->_data[$this->_position++]);
+ $val = $nextByte & 0x7F;
+
+ for ($shift=7; ($nextByte & 0x80) != 0; $shift += 7) {
+ $nextByte = ord($this->_data[$this->_position++]);
+ $val |= ($nextByte & 0x7F) << $shift;
+ }
+ return $val;
+ }
+
+ /**
+ * Writes a variable-length integer to the end of file.
+ *
+ * @param integer $value
+ */
+ public function writeVInt($value)
+ {
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ settype($value, 'integer');
+ while ($value > 0x7F) {
+ $this->_data .= chr( ($value & 0x7F)|0x80 );
+ $value >>= 7;
+ }
+ $this->_data .= chr($value);
+
+ $this->_position = strlen($this->_data);
+ }
+
+
+ /**
+ * Reads a string from the current position in the file
+ * and advances the file pointer.
+ *
+ * @return string
+ */
+ public function readString()
+ {
+ $strlen = $this->readVInt();
+ if ($strlen == 0) {
+ return '';
+ } else {
+ /**
+ * This implementation supports only Basic Multilingual Plane
+ * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
+ * "supplementary characters" (characters whose code points are
+ * greater than 0xFFFF)
+ * Java 2 represents these characters as a pair of char (16-bit)
+ * values, the first from the high-surrogates range (0xD800-0xDBFF),
+ * the second from the low-surrogates range (0xDC00-0xDFFF). Then
+ * they are encoded as usual UTF-8 characters in six bytes.
+ * Standard UTF-8 representation uses four bytes for supplementary
+ * characters.
+ */
+
+ $str_val = substr($this->_data, $this->_position, $strlen);
+ $this->_position += $strlen;
+
+ for ($count = 0; $count < $strlen; $count++ ) {
+ if (( ord($str_val[$count]) & 0xC0 ) == 0xC0) {
+ $addBytes = 1;
+ if (ord($str_val[$count]) & 0x20 ) {
+ $addBytes++;
+
+ // Never used. Java2 doesn't encode strings in four bytes
+ if (ord($str_val[$count]) & 0x10 ) {
+ $addBytes++;
+ }
+ }
+ $str_val .= substr($this->_data, $this->_position, $addBytes);
+ $this->_position += $addBytes;
+ $strlen += $addBytes;
+
+ // Check for null character. Java2 encodes null character
+ // in two bytes.
+ if (ord($str_val[$count]) == 0xC0 &&
+ ord($str_val[$count+1]) == 0x80 ) {
+ $str_val[$count] = 0;
+ $str_val = substr($str_val,0,$count+1)
+ . substr($str_val,$count+2);
+ }
+ $count += $addBytes;
+ }
+ }
+
+ return $str_val;
+ }
+ }
+
+ /**
+ * Writes a string to the end of file.
+ *
+ * @param string $str
+ * @throws Zend_Search_Lucene_Exception
+ */
+ public function writeString($str)
+ {
+ /**
+ * This implementation supports only Basic Multilingual Plane
+ * (BMP) characters (from 0x0000 to 0xFFFF) and doesn't support
+ * "supplementary characters" (characters whose code points are
+ * greater than 0xFFFF)
+ * Java 2 represents these characters as a pair of char (16-bit)
+ * values, the first from the high-surrogates range (0xD800-0xDBFF),
+ * the second from the low-surrogates range (0xDC00-0xDFFF). Then
+ * they are encoded as usual UTF-8 characters in six bytes.
+ * Standard UTF-8 representation uses four bytes for supplementary
+ * characters.
+ */
+
+ // We do not need to check if file position points to the end of "file".
+ // Only append operation is supported now
+
+ // convert input to a string before iterating string characters
+ settype($str, 'string');
+
+ $chars = $strlen = strlen($str);
+ $containNullChars = false;
+
+ for ($count = 0; $count < $strlen; $count++ ) {
+ /**
+ * String is already in Java 2 representation.
+ * We should only calculate actual string length and replace
+ * \x00 by \xC0\x80
+ */
+ if ((ord($str[$count]) & 0xC0) == 0xC0) {
+ $addBytes = 1;
+ if (ord($str[$count]) & 0x20 ) {
+ $addBytes++;
+
+ // Never used. Java2 doesn't encode strings in four bytes
+ // and we dont't support non-BMP characters
+ if (ord($str[$count]) & 0x10 ) {
+ $addBytes++;
+ }
+ }
+ $chars -= $addBytes;
+
+ if (ord($str[$count]) == 0 ) {
+ $containNullChars = true;
+ }
+ $count += $addBytes;
+ }
+ }
+
+ if ($chars < 0) {
+ require_once 'Zend/Search/Lucene/Exception.php';
+ throw new Zend_Search_Lucene_Exception('Invalid UTF-8 string');
+ }
+
+ $this->writeVInt($chars);
+ if ($containNullChars) {
+ $this->_data .= str_replace($str, "\x00", "\xC0\x80");
+
+ } else {
+ $this->_data .= $str;
+ }
+
+ $this->_position = strlen($this->_data);
+ }
+
+
+ /**
+ * Reads binary data from the current position in the file
+ * and advances the file pointer.
+ *
+ * @return string
+ */
+ public function readBinary()
+ {
+ $length = $this->readVInt();
+ $returnValue = substr($this->_data, $this->_position, $length);
+ $this->_position += $length;
+ return $returnValue;
+ }
+}
+