Continued:
authorRoland Haeder <roland@mxchange.org>
Mon, 11 May 2015 12:00:21 +0000 (14:00 +0200)
committerRoland Haeder <roland@mxchange.org>
Mon, 11 May 2015 12:00:21 +0000 (14:00 +0200)
- Several improvements for binary file classes (can't remember all)
- contrib/lfbdb2/<read|write>.php is now using auto-dection of 64-bit systems (very easy check).

Signed-off-by: Roland H├Ąder <roland@mxchange.org>
23 files changed:
contrib/chash/chash.php
contrib/lfdb2/read.php
contrib/lfdb2/write.php
inc/classes/interfaces/block/class_Block.php
inc/classes/interfaces/index/stack/class_IndexableStack.php
inc/classes/interfaces/iterator/class_SeekableWritableFileIterator.php
inc/classes/main/class_BaseFrameworkSystem.php
inc/classes/main/database/backend/class_CachedLocalFileDatabase.php
inc/classes/main/debug/class_DebugConsoleOutput.php
inc/classes/main/debug/class_DebugErrorLogOutput.php
inc/classes/main/debug/class_DebugWebOutput.php
inc/classes/main/file_directories/binary/class_BaseBinaryFile.php
inc/classes/main/file_directories/binary/index/class_IndexFile.php
inc/classes/main/file_directories/binary/stack/class_StackFile.php
inc/classes/main/file_directories/text/class_BaseTextFile.php
inc/classes/main/index/class_BaseIndex.php
inc/classes/main/index/file_stack/class_FileStackIndex.php
inc/classes/main/iterator/file/class_FileIterator.php
inc/classes/main/output/class_ConsoleOutput.php
inc/classes/main/output/class_WebOutput.php
inc/classes/main/rng/class_RandomNumberGenerator.php
inc/classes/main/stacker/file/class_BaseFileStack.php
inc/loader/class_ClassLoader.php

index c37216a..34a30b5 100644 (file)
@@ -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]);
index 8779b65..ae573df 100644 (file)
@@ -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');
index 25cdbbd..25941cd 100644 (file)
@@ -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');
index 32cad91..12c99f0 100644 (file)
@@ -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]
index dfc9581..64b8805 100644 (file)
  * 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]
index 536474c..26ed97d 100644 (file)
@@ -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]
index 7087af8..2b2d268 100644 (file)
@@ -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
@@ -541,6 +569,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
         *
         * @param       $realClass      Class name (string)
@@ -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]
index 4e1a6a6..7e486b1 100644 (file)
@@ -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 ...');
index 79ac849..285c955 100644 (file)
@@ -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);
        }
 
index fa07f07..7496383 100644 (file)
@@ -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);
        }
 
index cf47ad0..0da9db7 100644 (file)
@@ -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);
        }
 
index a6cfad6..8debce7 100644 (file)
@@ -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]
index 458dce2..8fd85d3 100644 (file)
@@ -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]
index 95eb82a..cf562b8 100644 (file)
@@ -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]
index 04954d2..ca7ff6e 100644 (file)
@@ -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);
        }
 }
index 6dd651c..e28facc 100644 (file)
@@ -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]
index e313ad8..307d399 100644 (file)
@@ -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]
index b400824..ff98173 100644 (file)
@@ -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]
index c2ff3d4..e920c6e 100644 (file)
@@ -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);
        }
 
index c000ebc..58d2db0 100644 (file)
@@ -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);
        }
 
index fb74071..a30fb0d 100644 (file)
@@ -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
index 81648d5..14972d7 100644 (file)
@@ -28,6 +28,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
         *
         * @param       $className      Name of the class
@@ -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;
@@ -481,6 +512,46 @@ class BaseFileStack extends BaseStacker {
        }
 
        /**
+        * 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
         *
         * @return      $fileSize       Size of currently loaded file
@@ -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]
index 3c72647..31fc9de 100644 (file)
@@ -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;