From bde1a7331a8a5c1e4a304583c0db268026aeb8a8 Mon Sep 17 00:00:00 2001 From: Roland Haeder Date: Mon, 11 May 2015 14:00:21 +0200 Subject: [PATCH] Continued: - Several improvements for binary file classes (can't remember all) - contrib/lfbdb2/.php is now using auto-dection of 64-bit systems (very easy check). MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- contrib/chash/chash.php | 4 +- contrib/lfdb2/read.php | 2 +- contrib/lfdb2/write.php | 2 +- inc/classes/interfaces/block/class_Block.php | 38 +++++ .../index/stack/class_IndexableStack.php | 8 ++ .../class_SeekableWritableFileIterator.php | 28 ++++ .../main/class_BaseFrameworkSystem.php | 132 +++++++++++++++++- .../backend/class_CachedLocalFileDatabase.php | 4 +- .../main/debug/class_DebugConsoleOutput.php | 2 +- .../main/debug/class_DebugErrorLogOutput.php | 2 +- .../main/debug/class_DebugWebOutput.php | 2 +- .../binary/class_BaseBinaryFile.php | 35 ++++- .../binary/index/class_IndexFile.php | 27 ++++ .../binary/stack/class_StackFile.php | 39 ++++++ .../text/class_BaseTextFile.php | 4 +- inc/classes/main/index/class_BaseIndex.php | 40 ++++++ .../index/file_stack/class_FileStackIndex.php | 22 +++ .../main/iterator/file/class_FileIterator.php | 38 +++++ .../main/output/class_ConsoleOutput.php | 2 +- inc/classes/main/output/class_WebOutput.php | 2 +- .../main/rng/class_RandomNumberGenerator.php | 4 +- .../main/stacker/file/class_BaseFileStack.php | 132 +++++++++++++++++- inc/loader/class_ClassLoader.php | 4 +- 23 files changed, 540 insertions(+), 33 deletions(-) diff --git a/contrib/chash/chash.php b/contrib/chash/chash.php index c37216ab..34a30b5b 100644 --- a/contrib/chash/chash.php +++ b/contrib/chash/chash.php @@ -262,7 +262,7 @@ function flushCheckPointFile ($hash) { 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 @@ -407,7 +407,7 @@ if (is_readable(CHECK_POINT)) { $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]); diff --git a/contrib/lfdb2/read.php b/contrib/lfdb2/read.php index 8779b654..ae573df2 100644 --- a/contrib/lfdb2/read.php +++ b/contrib/lfdb2/read.php @@ -14,7 +14,7 @@ $__factor = constant('__FACTOR_32'); $__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'); diff --git a/contrib/lfdb2/write.php b/contrib/lfdb2/write.php index 25cdbbdb..25941cdd 100644 --- a/contrib/lfdb2/write.php +++ b/contrib/lfdb2/write.php @@ -20,7 +20,7 @@ $__right = constant('__RIGHT_32'); $__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'); diff --git a/inc/classes/interfaces/block/class_Block.php b/inc/classes/interfaces/block/class_Block.php index 32cad910..12c99f0f 100644 --- a/inc/classes/interfaces/block/class_Block.php +++ b/inc/classes/interfaces/block/class_Block.php @@ -110,6 +110,44 @@ interface Block extends FrameworkInterface { * @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] diff --git a/inc/classes/interfaces/index/stack/class_IndexableStack.php b/inc/classes/interfaces/index/stack/class_IndexableStack.php index dfc9581e..64b88056 100644 --- a/inc/classes/interfaces/index/stack/class_IndexableStack.php +++ b/inc/classes/interfaces/index/stack/class_IndexableStack.php @@ -22,6 +22,14 @@ * along with this program. If not, see . */ 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] diff --git a/inc/classes/interfaces/iterator/class_SeekableWritableFileIterator.php b/inc/classes/interfaces/iterator/class_SeekableWritableFileIterator.php index 536474c2..26ed97dd 100644 --- a/inc/classes/interfaces/iterator/class_SeekableWritableFileIterator.php +++ b/inc/classes/interfaces/iterator/class_SeekableWritableFileIterator.php @@ -154,6 +154,34 @@ interface SeekableWritableFileIterator extends SeekableIterator { * @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] diff --git a/inc/classes/main/class_BaseFrameworkSystem.php b/inc/classes/main/class_BaseFrameworkSystem.php index 7087af8d..2b2d2683 100644 --- a/inc/classes/main/class_BaseFrameworkSystem.php +++ b/inc/classes/main/class_BaseFrameworkSystem.php @@ -253,6 +253,34 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { */ 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.... * ***********************/ @@ -502,7 +530,7 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { } /** - * 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 @@ -517,7 +545,7 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { } /** - * 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 @@ -529,7 +557,7 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { } /** - * 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 @@ -540,6 +568,36 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { )); } + /** + * 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 * @@ -3072,6 +3130,74 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface { // ... 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] diff --git a/inc/classes/main/database/backend/class_CachedLocalFileDatabase.php b/inc/classes/main/database/backend/class_CachedLocalFileDatabase.php index 4e1a6a6a..7e486b1f 100644 --- a/inc/classes/main/database/backend/class_CachedLocalFileDatabase.php +++ b/inc/classes/main/database/backend/class_CachedLocalFileDatabase.php @@ -177,7 +177,7 @@ class CachedLocalFileDatabase extends BaseDatabaseBackend implements DatabaseBac $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 . '.'); @@ -200,7 +200,7 @@ class CachedLocalFileDatabase extends BaseDatabaseBackend implements DatabaseBac //* 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 ...'); diff --git a/inc/classes/main/debug/class_DebugConsoleOutput.php b/inc/classes/main/debug/class_DebugConsoleOutput.php index 79ac8499..285c955d 100644 --- a/inc/classes/main/debug/class_DebugConsoleOutput.php +++ b/inc/classes/main/debug/class_DebugConsoleOutput.php @@ -117,7 +117,7 @@ class DebugConsoleOutput extends BaseFrameworkSystem implements Debugger, Output * @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); } diff --git a/inc/classes/main/debug/class_DebugErrorLogOutput.php b/inc/classes/main/debug/class_DebugErrorLogOutput.php index fa07f077..74963830 100644 --- a/inc/classes/main/debug/class_DebugErrorLogOutput.php +++ b/inc/classes/main/debug/class_DebugErrorLogOutput.php @@ -114,7 +114,7 @@ class DebugErrorLogOutput extends BaseFrameworkSystem implements Debugger, Outpu * @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); } diff --git a/inc/classes/main/debug/class_DebugWebOutput.php b/inc/classes/main/debug/class_DebugWebOutput.php index cf47ad07..0da9db7e 100644 --- a/inc/classes/main/debug/class_DebugWebOutput.php +++ b/inc/classes/main/debug/class_DebugWebOutput.php @@ -103,7 +103,7 @@ class DebugWebOutput extends BaseFrameworkSystem implements Debugger, OutputStre * @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); } diff --git a/inc/classes/main/file_directories/binary/class_BaseBinaryFile.php b/inc/classes/main/file_directories/binary/class_BaseBinaryFile.php index a6cfad6c..8debce70 100644 --- a/inc/classes/main/file_directories/binary/class_BaseBinaryFile.php +++ b/inc/classes/main/file_directories/binary/class_BaseBinaryFile.php @@ -33,19 +33,24 @@ class BaseBinaryFile extends BaseAbstractFile { 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 @@ -58,9 +63,9 @@ class BaseBinaryFile extends BaseAbstractFile { const LENGTH_POSITION = 20; /** - * Length of name + * Length of group */ - const LENGTH_NAME = 10; + const LENGTH_GROUP = 10; /** * Maximum length of entry type @@ -822,6 +827,24 @@ class BaseBinaryFile extends BaseAbstractFile { // 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] diff --git a/inc/classes/main/file_directories/binary/index/class_IndexFile.php b/inc/classes/main/file_directories/binary/index/class_IndexFile.php index 458dce20..8fd85d3d 100644 --- a/inc/classes/main/file_directories/binary/index/class_IndexFile.php +++ b/inc/classes/main/file_directories/binary/index/class_IndexFile.php @@ -52,6 +52,33 @@ class IndexFile extends BaseBinaryFile implements Block { // 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] diff --git a/inc/classes/main/file_directories/binary/stack/class_StackFile.php b/inc/classes/main/file_directories/binary/stack/class_StackFile.php index 95eb82a7..cf562b87 100644 --- a/inc/classes/main/file_directories/binary/stack/class_StackFile.php +++ b/inc/classes/main/file_directories/binary/stack/class_StackFile.php @@ -52,6 +52,45 @@ class StackFile extends BaseBinaryFile implements Block { // 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] diff --git a/inc/classes/main/file_directories/text/class_BaseTextFile.php b/inc/classes/main/file_directories/text/class_BaseTextFile.php index 04954d23..ca7ff6ef 100644 --- a/inc/classes/main/file_directories/text/class_BaseTextFile.php +++ b/inc/classes/main/file_directories/text/class_BaseTextFile.php @@ -52,7 +52,7 @@ class BaseTextFile extends BaseAbstractFile { */ 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); } @@ -69,7 +69,7 @@ class BaseTextFile extends BaseAbstractFile { * 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); } } diff --git a/inc/classes/main/index/class_BaseIndex.php b/inc/classes/main/index/class_BaseIndex.php index 6dd651ca..e28faccd 100644 --- a/inc/classes/main/index/class_BaseIndex.php +++ b/inc/classes/main/index/class_BaseIndex.php @@ -294,6 +294,46 @@ class BaseIndex extends BaseFrameworkSystem { // 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] diff --git a/inc/classes/main/index/file_stack/class_FileStackIndex.php b/inc/classes/main/index/file_stack/class_FileStackIndex.php index e313ad83..307d3996 100644 --- a/inc/classes/main/index/file_stack/class_FileStackIndex.php +++ b/inc/classes/main/index/file_stack/class_FileStackIndex.php @@ -48,6 +48,28 @@ class FileStackIndex extends BaseIndex implements IndexableStack, Registerable { // 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] diff --git a/inc/classes/main/iterator/file/class_FileIterator.php b/inc/classes/main/iterator/file/class_FileIterator.php index b4008244..ff981732 100644 --- a/inc/classes/main/iterator/file/class_FileIterator.php +++ b/inc/classes/main/iterator/file/class_FileIterator.php @@ -286,6 +286,44 @@ class FileIterator extends BaseIterator implements SeekableWritableFileIterator // 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] diff --git a/inc/classes/main/output/class_ConsoleOutput.php b/inc/classes/main/output/class_ConsoleOutput.php index c2ff3d4f..e920c6ea 100644 --- a/inc/classes/main/output/class_ConsoleOutput.php +++ b/inc/classes/main/output/class_ConsoleOutput.php @@ -110,7 +110,7 @@ class ConsoleOutput extends BaseFrameworkSystem implements OutputStreamer { * @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); } diff --git a/inc/classes/main/output/class_WebOutput.php b/inc/classes/main/output/class_WebOutput.php index c000ebcc..58d2db0a 100644 --- a/inc/classes/main/output/class_WebOutput.php +++ b/inc/classes/main/output/class_WebOutput.php @@ -94,7 +94,7 @@ class WebOutput extends BaseFrameworkSystem implements OutputStreamer, Registera * @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); } diff --git a/inc/classes/main/rng/class_RandomNumberGenerator.php b/inc/classes/main/rng/class_RandomNumberGenerator.php index fb74071e..a30fb0dd 100644 --- a/inc/classes/main/rng/class_RandomNumberGenerator.php +++ b/inc/classes/main/rng/class_RandomNumberGenerator.php @@ -122,11 +122,11 @@ class RandomNumberGenerator extends BaseFrameworkSystem { $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 diff --git a/inc/classes/main/stacker/file/class_BaseFileStack.php b/inc/classes/main/stacker/file/class_BaseFileStack.php index 81648d58..14972d73 100644 --- a/inc/classes/main/stacker/file/class_BaseFileStack.php +++ b/inc/classes/main/stacker/file/class_BaseFileStack.php @@ -27,6 +27,21 @@ class BaseFileStack extends BaseStacker { */ 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 * @@ -212,8 +227,18 @@ class BaseFileStack extends BaseStacker { 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); } /** @@ -231,7 +256,7 @@ class BaseFileStack extends BaseStacker { } // END - if // Now get the last value - $this->partialStub('stackerName=' . $stackerName); + /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); $value = NULL; // Return it @@ -253,7 +278,7 @@ class BaseFileStack extends BaseStacker { } // END - if // Now get the first value - $this->partialStub('stackerName=' . $stackerName); + /* NOISY-DEBUG: */ $this->partialStub('[' . __METHOD__ . ':' . __LINE__ . '] stackerName=' . $stackerName); $value = NULL; // Return it @@ -275,7 +300,7 @@ class BaseFileStack extends BaseStacker { } // 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; } @@ -294,7 +319,7 @@ class BaseFileStack extends BaseStacker { } // 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; } @@ -399,7 +424,13 @@ class BaseFileStack extends BaseStacker { */ 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; @@ -480,6 +511,46 @@ class BaseFileStack extends BaseStacker { 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 * @@ -489,6 +560,53 @@ class BaseFileStack extends BaseStacker { // 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] diff --git a/inc/loader/class_ClassLoader.php b/inc/loader/class_ClassLoader.php index 3c72647f..31fc9de2 100644 --- a/inc/loader/class_ClassLoader.php +++ b/inc/loader/class_ClassLoader.php @@ -133,7 +133,7 @@ class ClassLoader { // 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 @@ -240,7 +240,7 @@ class ClassLoader { $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; -- 2.39.2