base64_encode((float) $GLOBALS['nonce']) . ':' .
$hash . ':' .
$GLOBALS['root_hash'] . ':' .
- base64_encode(gzcompress(serialize($GLOBALS['found_hashes'])))
+ base64_encode(gzcompress(json_encode($GLOBALS['found_hashes'])))
);
// Set time
$GLOBALS['hash_cycles'] = intval($data[5]);
$GLOBALS['nonce'] = (float) base64_decode($data[6]);
$GLOBALS['root_hash'] = $data[8];
- $GLOBALS['found_hashes'] = unserialize(gzuncompress(base64_decode($data[9])));
+ $GLOBALS['found_hashes'] = json_decode(gzuncompress(base64_decode($data[9])));
// Set modula hash
setModulaHash($data[7]);
$__format = constant('__FORMAT_READ_32');
$__step = constant('__STEP_32');
-if ((isset($_SERVER['argv'][1])) && ($_SERVER['argv'][1] == '-64')) {
+if (PHP_INT_SIZE === 8) {
// Use 64-bit
$__factor = constant('__FACTOR_64');
$__format = constant('__FORMAT_READ_64');
$__format = constant('__FORMAT_WRITE_32');
$__step = constant('__STEP_32');
-if ((isset($_SERVER['argv'][1])) && ($_SERVER['argv'][1] == '-64')) {
+if (PHP_INT_SIZE === 8) {
// Use 64-bit
$__factor = constant('__FACTOR_64');
$__left = constant('__LEFT_64');
* @return $fileSize Size of currently loaded file
*/
function getFileSize ();
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ */
+ function writeValueToFile ($groupId, $rawData);
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ */
+ function writeDataToFreeGap ($groupId, $hash, $encoded);
+
+ /**
+ * Writes data at given position
+ *
+ * @param $seekPosition Seek position
+ * @param $data Data to be written
+ * @param $flushHeader Whether to flush the header (default: flush)
+ * @return void
+ */
+ function writeData ($seekPosition, $data, $flushHeader = TRUE);
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ */
+ function searchNextGap ($length);
}
// [EOF]
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
interface IndexableStack extends Indexable, CalculatableBlock {
+ /**
+ * Adds given hash to an index file
+ *
+ * @param $stackName Name of stack to add hash
+ * @param $data Hash and gap position to be added to the index
+ * @return void
+ */
+ function addHashToIndex ($stackName, array $data);
}
// [EOF]
* @return $seekPosition Current seek position (stored here in object)
*/
function getSeekPosition ();
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ */
+ function writeValueToFile ($groupId, $value);
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ */
+ function writeDataToFreeGap ($groupId, $hash, $encoded);
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ */
+ function searchNextGap ($length);
}
// [EOF]
*/
private $controllerName = '';
+ /**
+ * Array with bitmasks and such for pack/unpack methods to support both
+ * 32-bit and 64-bit systems
+ */
+ private $packingData = array(
+ 32 => array(
+ 'step' => 3,
+ 'left' => 0xffff0000,
+ 'right' => 0x0000ffff,
+ 'factor' => 16,
+ 'format' => 'II',
+ ),
+ 64 => array(
+ 'step' => 7,
+ 'left' => 0xffffffff00000000,
+ 'right' => 0x00000000ffffffff,
+ 'factor' => 32,
+ 'format' => 'NN'
+ )
+ );
+
+ /**
+ * Simple 64-bit check, thanks to "Salman A" from stackoverflow.com:
+ *
+ * The integer size is 4 bytes on 32-bit and 8 bytes on a 64-bit system.
+ */
+ private $archArrayElement = (PHP_INT_SIZE === 8 ? 64 : 32);
+
/***********************
* Exception codes.... *
***********************/
}
/**
- * Magic function to catch setting of missing but set class fields/attributes
+ * Magic method to catch setting of missing but set class fields/attributes
*
* @param $name Name of the field/attribute
* @param $value Value to store
}
/**
- * Magic function to catch getting of missing fields/attributes
+ * Magic method to catch getting of missing fields/attributes
*
* @param $name Name of the field/attribute
* @return void
}
/**
- * Magic function to catch unsetting of missing fields/attributes
+ * Magic method to catch unsetting of missing fields/attributes
*
* @param $name Name of the field/attribute
* @return void
));
}
+ /**
+ * Magic method to catch object serialization
+ *
+ * @return $unsupported Unsupported method
+ * @throws UnsupportedOperationException Objects of this framework cannot be serialized
+ */
+ public final function __sleep () {
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Magic method to catch object deserialization
+ *
+ * @return $unsupported Unsupported method
+ * @throws UnsupportedOperationException Objects of this framework cannot be serialized
+ */
+ public final function __wakeup () {
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Magic method to catch calls when an object instance is called
+ *
+ * @return $unsupported Unsupported method
+ * @throws UnsupportedOperationException Objects of this framework cannot be serialized
+ */
+ public final function __invoke () {
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
/**
* Setter for the real class name
*
// ... and return it
return $translated;
}
+
+ /**
+ * Encodes raw data (almost any type) by "serializing" it and then pack it
+ * into a "binary format".
+ *
+ * @param $rawData Raw data (almost any type)
+ * @return $encoded Encoded data
+ */
+ protected function encodeData ($rawData) {
+ // Make sure no objects or resources pass through
+ assert(!is_object($rawData));
+ assert(!is_resource($rawData));
+
+ // First "serialize" it (json_encode() is faster than serialize())
+ $encoded = $this->packString(json_encode($rawData));
+
+ // And return it
+ return $encoded;
+ }
+
+ /**
+ * Pack a string into a "binary format". Please execuse me that this is
+ * widely undocumented. :-(
+ *
+ * @param $str Unpacked string
+ * @return $packed Packed string
+ * @todo Improve documentation
+ */
+ protected function packString ($str) {
+ // Debug message
+ //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__)->debugOutput('str=' . $str . ' - CALLED!');
+
+ // First compress the string (gzcompress is okay)
+ $str = gzcompress($str);
+
+ // Init variable
+ $packed = '';
+
+ // And start the "encoding" loop
+ for ($idx = 0; $idx < strlen($str); $idx += $this->packingData[$this->archArrayElement]['step']) {
+ $big = 0;
+ for ($i = 0; $i < $this->packingData[$this->archArrayElement]['step']; $i++) {
+ $factor = ($this->packingData[$this->archArrayElement]['step'] - 1 - $i);
+
+ if (($idx + $i) <= strlen($str)) {
+ $ord = ord(substr($str, ($idx + $i), 1));
+
+ $add = $ord * pow(256, $factor);
+
+ $big += $add;
+
+ //print 'idx=' . $idx . ',i=' . $i . ',ord=' . $ord . ',factor=' . $factor . ',add=' . $add . ',big=' . $big . PHP_EOL;
+ } // END - if
+ } // END - for
+
+ $l = ($big & $this->packingData[$this->archArrayElement]['left']) >>$this->packingData[$this->archArrayElement]['factor'];
+ $r = $big & $this->packingData[$this->archArrayElement]['right'];
+
+ $chunk = str_pad(pack($this->packingData[$this->archArrayElement]['format'], $l, $r), 8, '0', STR_PAD_LEFT);
+ //* NOISY-DEBUG */ print 'big=' . $big . ',chunk('.strlen($chunk) . ')='.md5($chunk).PHP_EOL;
+
+ $packed .= $chunk;
+ } // END - for
+
+ // Return it
+ //* NOISY-DEBUG */ self::createDebugInstance(__CLASS__)->debugOutput('packed=' . $packed . ' - EXIT!');
+ return $packed;
+ }
}
// [EOF]
$serializedData = $this->getCompressorChannel()->getCompressor()->decompressStream($compressedData);
// Unserialize it
- $dataArray = unserialize($serializedData);
+ $dataArray = json_decode($serializedData, TRUE);
// Debug message
//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Read ' . count($dataArray) . ' elements from database file ' . $fqfn . '.');
//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataArray=' . print_r($dataArray, TRUE));
// Serialize and compress it
- $compressedData = $this->getCompressorChannel()->getCompressor()->compressStream(serialize($dataArray));
+ $compressedData = $this->getCompressorChannel()->getCompressor()->compressStream(json_encode($dataArray));
// Write data
//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: Writing ' . strlen($compressedData) . ' bytes ...');
* @throws UnsupportedOperationException If this method is called
*/
public function seek ($offset, $whence = SEEK_SET) {
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
* @throws UnsupportedOperationException If this method is called
*/
public function seek ($offset, $whence = SEEK_SET) {
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
* @throws UnsupportedOperationException If this method is called
*/
public function seek ($offset, $whence = SEEK_SET) {
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
const SEPARATOR_HEADER_ENTRIES = 0x02;
/**
- * Separator hash->name
+ * Separator group->hash
*/
- const SEPARATOR_HASH_NAME = 0x03;
+ const SEPARATOR_GROUP_HASH = 0x03;
+
+ /**
+ * Separator hash->value
+ */
+ const SEPARATOR_HASH_VALUE = 0x04;
/**
* Separator entry->entry
*/
- const SEPARATOR_ENTRIES = 0x04;
+ const SEPARATOR_ENTRIES = 0x05;
/**
* Separator type->position
*/
- const SEPARATOR_TYPE_POSITION = 0x05;
+ const SEPARATOR_TYPE_POSITION = 0x06;
/**
* Length of count
const LENGTH_POSITION = 20;
/**
- * Length of name
+ * Length of group
*/
- const LENGTH_NAME = 10;
+ const LENGTH_GROUP = 10;
/**
* Maximum length of entry type
// Call block instance
$this->getBlockInstance()->flushFileHeader();
}
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ */
+ public function searchNextGap ($length) {
+ // If the file is only gaps, no need to seek
+ if ($this->isFileOnlyGaps()) {
+ // The first empty block is the first one right after the header
+ return ($this->getHeaderSize() + 1);
+ } // END - if
+
+ // @TODO Unfinished
+ $this->partialStub('length=' . $length);
+ }
}
// [EOF]
// Return the prepared instance
return $fileInstance;
}
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ * @throws UnsupportedOperationException If this method is called
+ */
+ public function writeValueToFile ($groupId, $value) {
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',value[' . gettype($value) . ']=' . print_r($value, TRUE));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ * @throws UnsupportedOperationException If this method is called
+ */
+ public function writeDataToFreeGap ($groupId, $hash, $encoded) {
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',encoded()=' . strlen($encoded));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
}
// [EOF]
// Return the prepared instance
return $fileInstance;
}
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ */
+ public function writeValueToFile ($groupId, $value) {
+ // Make sure no objects/resources are added as the serialization may fail
+ assert(!is_object($value));
+ assert(!is_resource($value));
+
+ // Encode/convert the value into a "binary format"
+ $encoded = $this->encodeData($value);
+
+ // Get a strong hash for the "encoded" data
+ $hash = self::hash($encoded);
+
+ // Then write it to the next free gap
+ $data = $this->getBlockInstance()->writeDataToFreeGap($groupId, $hash, $encoded);
+
+ // Return info
+ return $data;
+ }
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ * @throws UnsupportedOperationException If this method is called
+ */
+ public function writeDataToFreeGap ($groupId, $hash, $encoded) {
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',hash=' . $hash . ',encoded()=' . strlen($encoded));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
}
// [EOF]
*/
public function seek ($offset, $whence = SEEK_SET) {
// Not possible in text files
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
* This class (or its implementations) are special file readers/writers.
* There is no need to read/write the whole file.
*/
- self::createDebugInstance(__CLASS__)->debugOutput('fqfn=' . $fqfn);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] fqfn=' . $fqfn);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
}
// Call iterator's method
return $this->getIteratorInstance()->getFileSize();
}
+
+ /**
+ * Writes data at given position
+ *
+ * @param $seekPosition Seek position
+ * @param $data Data to be written
+ * @param $flushHeader Whether to flush the header (default: flush)
+ * @return void
+ * @throws UnsupportedOperationException This method is not (and maybe never will be) supported
+ */
+ public function writeData ($seekPosition, $data, $flushHeader = TRUE) {
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data[]=%s,flushHeader=%d', __METHOD__, __LINE__, $seekPosition, gettype($data), intval($flushHeader)));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ * @throws UnsupportedOperationException If this method is called
+ */
+ public function writeValueToFile ($groupId, $value) {
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',value[' . gettype($value) . ']=' . print_r($value, TRUE));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ */
+ public function writeDataToFreeGap ($groupId, $hash, $encoded) {
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] groupId=' . $groupId . ',hash=' . $hash . ',encoded()=' . strlen($encoded));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
}
// [EOF]
// Return the prepared instance
return $indexInstance;
}
+
+ /**
+ * Adds given hash to an index file
+ *
+ * @param $groupId Name of stack to add hash for
+ * @param $data Hash and gap position to be added to the index
+ * @return void
+ */
+ public function addHashToIndex ($groupId, array $data) {
+ $this->partialStub('groupId=' . $groupId . ',data=' . print_r($data, TRUE));
+ }
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ */
+ public function searchNextGap ($length) {
+ $this->partialStub('length=' . $length);
+ }
}
// [EOF]
// Call block instance
return $this->getBlockInstance()->getSeekPosition();
}
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ */
+ public function writeValueToFile ($groupId, $value) {
+ // Call block instance
+ return $this->getBlockInstance()->writeValueToFile($groupId, $value);
+ }
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ */
+ public function writeDataToFreeGap ($groupId, $hash, $encoded) {
+ // Call block instance
+ return $this->getBlockInstance()->writeDataToFreeGap($groupId, $hash, $encoded);
+ }
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ */
+ public function searchNextGap ($length) {
+ // Call block instance
+ print $this->getBlockInstance()->__toString() . PHP_EOL;
+ return $this->getBlockInstance()->searchNextGap($length);
+ }
}
// [EOF]
* @throws UnsupportedOperationException If this method is called
*/
public function seek ($offset, $whence = SEEK_SET) {
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
* @throws UnsupportedOperationException If this method is called
*/
public function seek ($offset, $whence = SEEK_SET) {
- self::createDebugInstance(__CLASS__)->debugOutput('offset=' . $offset . ',whence=' . $whence);
+ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] offset=' . $offset . ',whence=' . $whence);
throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
}
$this->fixedSalt = sha1(
$serverIp . ':' .
$extraInstance->__toString() . ':' .
- serialize($this->getDatabaseInstance()->getConnectionData())
+ json_encode($this->getDatabaseInstance()->getConnectionData())
);
} else {
// Without extra information
- $this->fixedSalt = sha1($serverIp . ':' . serialize($this->getDatabaseInstance()->getConnectionData()));
+ $this->fixedSalt = sha1($serverIp . ':' . json_encode($this->getDatabaseInstance()->getConnectionData()));
}
// One-way data we need for "extra-salting" the random number
*/
const STACK_MAGIC = 'STACKv0.1';
+ /**
+ * Name of array index for gap position
+ */
+ const ARRAY_INDEX_GAP_POSITION = 'gap';
+
+ /**
+ * Name of array index for hash
+ */
+ const ARRAY_INDEX_HASH = 'hash';
+
+ /**
+ * Name of array index for length of raw data
+ */
+ const ARRAY_INDEX_DATA_LENGTH = 'length';
+
/**
* Protected constructor
*
throw new FullStackerException(array($this, $stackerName, $value), self::EXCEPTION_STACKER_IS_FULL);
} // END - if
- // Now add the value to the stack
- $this->partialStub('stackerName=' . $stackerName . ',value[]=' . gettype($value));
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName . ',value[' . gettype($value) . ']=' . print_r($value, TRUE));
+
+ // No objects/resources are allowed as their serialization takes to long
+ assert(!is_object($value));
+ assert(!is_resource($value));
+
+ // Now add the value to the file stack (which returns a hash)
+ $data = $this->getIteratorInstance()->writeValueToFile($stackerName, $value);
+
+ // Add the hash and gap position to the index
+ $this->getIndexInstance()->addHashToIndex($stackerName, $data);
}
/**
} // END - if
// Now get the last value
- $this->partialStub('stackerName=' . $stackerName);
+ /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName);
$value = NULL;
// Return it
} // END - if
// Now get the first value
- $this->partialStub('stackerName=' . $stackerName);
+ /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName);
$value = NULL;
// Return it
} // END - if
// Now, remove the last entry, we don't care about the return value here, see elseif() block above
- $this->partialStub('stackerName=' . $stackerName);
+ /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName);
return NULL;
}
} // END - if
// Now, remove the last entry, we don't care about the return value here, see elseif() block above
- $this->partialStub('stackerName=' . $stackerName);
+ /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName);
return NULL;
}
*/
public function calculateMinimumBlockLength () {
// Calulcate it
- $length = self::getHashLength() + strlen(chr(BaseBinaryFile::SEPARATOR_HASH_NAME)) + BaseBinaryFile::LENGTH_NAME + 1 + strlen(chr(BaseBinaryFile::SEPARATOR_ENTRIES));
+ $length =
+ // Length of entry group
+ BaseBinaryFile::LENGTH_GROUP + strlen(chr(BaseBinaryFile::SEPARATOR_GROUP_HASH)) +
+ // Hash + value
+ self::getHashLength() + strlen(chr(BaseBinaryFile::SEPARATOR_HASH_VALUE)) + 1 +
+ // Final separator
+ strlen(chr(BaseBinaryFile::SEPARATOR_ENTRIES));
// Return it
return $length;
throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
}
+ /**
+ * Writes data at given position
+ *
+ * @param $seekPosition Seek position
+ * @param $data Data to be written
+ * @param $flushHeader Whether to flush the header (default: flush)
+ * @return void
+ * @throws UnsupportedOperationException This method is not (and maybe never will be) supported
+ */
+ public function writeData ($seekPosition, $data, $flushHeader = TRUE) {
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data[]=%s,flushHeader=%d', __METHOD__, __LINE__, $seekPosition, gettype($data), intval($flushHeader)));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Writes given value to the file and returns a hash and gap position for it
+ *
+ * @param $groupId Group identifier
+ * @param $value Value to be added to the stack
+ * @return $data Hash and gap position
+ * @throws UnsupportedOperationException This method is not (and maybe never will be) supported
+ */
+ public function writeValueToFile ($groupId, $value) {
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] groupId=%s,value[%s]=%s', __METHOD__, __LINE__, $groupId, gettype($value), print_r($value, TRUE)));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
+ /**
+ * Searches for next suitable gap the given length of data can fit in
+ * including padding bytes.
+ *
+ * @param $length Length of raw data
+ * @return $seekPosition Found next gap's seek position
+ * @throws UnsupportedOperationException This method is not (and maybe never will be) supported
+ */
+ public function searchNextGap ($length) {
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] length=%s', __METHOD__, __LINE__, $length));
+ throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
+ }
+
/**
* "Getter" for file size
*
// Call iterator's method
return $this->getIteratorInstance()->getFileSize();
}
+
+ /**
+ * Writes given raw data to the file and returns a gap position and length
+ *
+ * @param $groupId Group identifier
+ * @param $hash Hash from encoded value
+ * @param $encoded Encoded value to be written to the file
+ * @return $data Gap position and length of the raw data
+ */
+ public function writeDataToFreeGap ($groupId, $hash, $encoded) {
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,encoded()=%s - CALLED!', __METHOD__, __LINE__, $groupId, $hash, strlen($encoded)));
+
+ // Raw data been written to the file
+ $rawData = sprintf('%s%s%s%s%s',
+ $groupId,
+ BaseBinaryFile::SEPARATOR_GROUP_HASH,
+ hex2bin($hash),
+ BaseBinaryFile::SEPARATOR_HASH_VALUE,
+ $encoded
+ );
+
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,rawData()=%s', __METHOD__, __LINE__, $groupId, $hash, strlen($rawData)));
+
+ // Search for next free gap
+ $gapPosition = $this->getIteratorInstance()->searchNextGap(strlen($rawData));
+
+ // Gap position cannot be smaller than header length + 1
+ assert($gapPosition > $this->getIteratorInstance()->getHeaderSize());
+
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,gapPosition=%s', __METHOD__, __LINE__, $groupId, $hash, $gapPosition));
+
+ // Then write the data at that gap
+ $this->getIteratorInstance()->writeData($gapPosition, $rawData);
+
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] groupId=%s,hash=%s,rawData()=%s - EXIT!', __METHOD__, __LINE__, $groupId, $hash, strlen($rawData)));
+
+ // Return gap position, hash and length of raw data
+ return array(
+ self::ARRAY_INDEX_GAP_POSITION => $gapPosition,
+ self::ARRAY_INDEX_HASH => $hash,
+ self::ARRAY_INDEX_DATA_LENGTH => strlen($rawData)
+ );
+ }
}
// [EOF]
// Skip here if already cached
if ($this->listCached === FALSE) {
// Writes the cache file of our list away
- $cacheContent = serialize($this->classes);
+ $cacheContent = json_encode($this->classes);
file_put_contents($this->listCacheFQFN, $cacheContent);
} // END - if
$cacheContent = file_get_contents($this->listCacheFQFN);
// And convert it
- $this->classes = unserialize($cacheContent);
+ $this->classes = json_decode($cacheContent);
// List has been restored from cache!
$this->listCached = TRUE;