namespace Org\Mxchange\CoreFramework\Filesystem\File;
// Import framework stuff
-use Org\Mxchange\CoreFramework\Factory\ObjectFactory;
-use Org\Mxchange\CoreFramework\Filesystem\Block;
-use Org\Mxchange\CoreFramework\Filesystem\Block\CalculatableBlock;
+use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
+use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint;
+use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
use Org\Mxchange\CoreFramework\Filesystem\File\BaseAbstractFile;
+use Org\Mxchange\CoreFramework\Index\Indexable;
+use Org\Mxchange\CoreFramework\Stack\File\StackableFile;
+use Org\Mxchange\CoreFramework\Traits\Index\IndexableTrait;
+use Org\Mxchange\CoreFramework\Traits\Stack\StackableTrait;
// Import SPL stuff
+use \BadMethodCallException;
+use \InvalidArgumentException;
+use \LogicException;
+use \OutOfBoundsException;
use \SplFileInfo;
+use \UnexpectedValueException;
/**
* A general binary file class
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-abstract class BaseBinaryFile extends BaseAbstractFile {
+abstract class BaseBinaryFile extends BaseAbstractFile implements BinaryFile {
+ // Load traits
+ use StackableTrait;
+ use IndexableTrait;
+
/**
* Separator for header data
*/
/**
* File header
*/
- private $header = array();
+ private $header = [];
/**
* Seek positions for gaps ("fragmentation")
*/
- private $gaps = array();
+ private $gaps = [];
/**
* Seek positions for damaged entries (e.g. mismatching hash sum, ...)
*/
- private $damagedEntries = array();
+ private $damagedEntries = [];
/**
* Back-buffer
* @param $className Name of the class
* @return void
*/
- protected function __construct ($className) {
+ protected function __construct (string $className) {
// Call parent constructor
parent::__construct($className);
}
/**
- * Checks whether the abstracted file only contains gaps by counting all
- * gaps' bytes together and compare it to total length.
+ * Setter for backBuffer field
*
- * @return $isGapsOnly Whether the abstracted file only contains gaps
+ * @param $backBuffer Characters to "store" in back-buffer
+ * @return void
*/
- private function isFileOnlyGaps () {
- // First/last gap found?
- /* Only for debugging
- if (isset($this->gaps[0])) {
- // Output first and last gap
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] this->gaps[0]=%s,this->gaps[%s]=%s', __METHOD__, __LINE__, print_r($this->gaps[0], true), (count($this->gaps) - 1), print_r($this->gaps[count($this->gaps) - 1], true)));
- } // END - if
- */
-
- // Now count every gap
- $gapsSize = 0;
- foreach ($this->gaps as $gap) {
- // Calculate size of found gap: end-start including both
- $gapsSize += ($gap[self::GAPS_INDEX_END] - $gap[self::GAPS_INDEX_START]);
- } // END - if
-
- // Debug output
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] gapsSize=%s,this->headerSize=%s', __METHOD__, __LINE__, $gapsSize, $this->getHeaderSize()));
-
- // Total gap size + header size must be same as file size
- $isGapsOnly = (($this->getHeaderSize() + $gapsSize) == $this->getFileSize());
+ private function setBackBuffer (string $backBuffer) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting backBuffer(%d)=%s - CALLED!', strlen($backBuffer), $backBuffer));
+ $this->backBuffer = $backBuffer;
+ }
- // Return status
- return $isGapsOnly;
+ /**
+ * Getter for backBuffer field
+ *
+ * @return $backBuffer Characters "stored" in back-buffer
+ */
+ private function getBackBuffer () {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->backBuffer(%d)=%s - CALLED!', strlen($this->backBuffer), $this->backBuffer));
+ return $this->backBuffer;
}
/**
- * Initializes counter for valid entries, arrays for damaged entries and
- * an array for gap seek positions. If you call this method on your own,
- * please re-analyze the file structure. So you are better to call
- * analyzeFile() instead of this method.
+ * Setter for current field
*
+ * @param $current Characters to set a currently loaded block
* @return void
*/
- public function initCountersGapsArray () {
- // Init counter and seek position
- $this->setCounter(0);
- $this->setSeekPosition(0);
+ private function setCurrentBlock (string $currentBlock) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting currentBlock(%d)=%s - CALLED!', strlen($currentBlock), $currentBlock));
+ $this->currentBlock = $currentBlock;
+ }
- // Init arrays
- $this->gaps = array();
- $this->damagedEntries = array();
+ /**
+ * Gets currently read data
+ *
+ * @return $current Currently read data
+ */
+ public function getCurrentBlock () {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->currentBlock(%d)=%s - CALLED!', strlen($this->currentBlock), $this->currentBlock));
+ return $this->currentBlock;
}
/**
* @return $totalEntries Size of file header
*/
public final function getHeaderSize () {
- // Get it
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->headerSize=%d - CALLED!', $this->headerSize));
return $this->headerSize;
}
* @param $headerSize Size of file header
* @return void
*/
- public final function setHeaderSize ($headerSize) {
- // Set it
+ public final function setHeaderSize (int $headerSize) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting headerSize=%d - CALLED!', $headerSize));
$this->headerSize = $headerSize;
}
* @return $seekPosition Current seek position (stored here in object)
*/
public final function getSeekPosition () {
- // Get it
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->seekPosition=%d - CALLED!', $this->seekPosition));
return $this->seekPosition;
}
* @param $seekPosition Current seek position (stored here in object)
* @return void
*/
- protected final function setSeekPosition ($seekPosition) {
- // And set it
+ protected final function setSeekPosition (int $seekPosition) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting seekPosition=%d - CALLED!', $seekPosition));
$this->seekPosition = $seekPosition;
}
/**
- * Updates seekPosition attribute from file to avoid to much access on file.
+ * Marks whole file as gaps-only (freshly created file
*
+ * @param $type Type of file
+ * @param $minimumBlockLength Minimum block length
* @return void
*/
- public function updateSeekPosition () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+ private function markFileGapsOnly (string $type, int $minimumBlockLength) {
+ // Very simple to do ...
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: type=%s,minimumBlockLength=%d - CALLED!', $type, $minimumBlockLength));
+ for ($idx = 0; $idx < FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_count'); $idx++) {
+ // Mark start and end position as gap
+ $this->addGap($idx * $minimumBlockLength, $idx * $minimumBlockLength + $minimumBlockLength);
+ }
- // Get key (= seek position)
- $seekPosition = $this->key();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Setting seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
+ }
- // And set it here
- $this->setSeekPosition($seekPosition);
+ /**
+ * Checks whether the abstracted file only contains gaps by counting all
+ * gaps' bytes together and compare it to total length.
+ *
+ * @return $isGapsOnly Whether the abstracted file only contains gaps
+ */
+ private function isFileGapsOnly () {
+ // Count every gap
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $gapsSize = 0;
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: this->gaps()=%d', count($this->gaps)));
+ foreach ($this->gaps as $gap) {
+ // Calculate size of found gap: end-start including both
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: gap[%s]=%d,ga[%s]=%d', self::GAPS_INDEX_START, $gap[self::GAPS_INDEX_START], self::GAPS_INDEX_END, $gap[self::GAPS_INDEX_END]));
+ $gapsSize += ($gap[self::GAPS_INDEX_END] - $gap[self::GAPS_INDEX_START]);
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: gapsSize=%d', $gapsSize));
+ }
+
+ // Total gap size + header size must be same as file size
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: gapsSize=%d,this->fileSize=%d', $gapsSize, $this->getFileSize()));
+ $isGapsOnly = ($gapsSize + 1 == $this->getFileSize());
+
+ // Return status
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isGapsOnly=%d - EXIT!', intval($isGapsOnly)));
+ return $isGapsOnly;
}
/**
- * Seeks to beginning of file, updates seek position in this object and
- * flushes the header.
+ * Adds a gap for given start and end position
*
+ * @param $startPosition Start seek position
+ * @param $endPosition End seek position
* @return void
*/
- protected function rewindUpdateSeekPosition () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
+ private function addGap(int $startPosition, int $endPosition) {
+ // Push to gaps array
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: startPosition=%d,endPosition=%d - CALLED!', $startPosition, $endPosition));
+ array_push($this->gaps, [
+ self::GAPS_INDEX_START => $startPosition,
+ self::GAPS_INDEX_END => $endPosition,
+ ]);
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
+ }
- // flushFileHeader must be callable
- assert(is_callable(array($this, 'flushFileHeader')));
+ /**
+ * Initializes the back-buffer by setting it to an empty string.
+ *
+ * @return void
+ */
+ private function initBackBuffer () {
+ // Simply call the setter
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $this->setBackBuffer('');
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
+ }
+ /**
+ * Seeks to beginning of file, updates seek position in this object and
+ * flushes the header.
+ *
+ * @param $flushHeader Wether the file's header should be flushed (default: false)
+ * @return void
+ */
+ protected function rewindUpdateSeekPosition (bool $flushHeader = false) {
// Seek to beginning of file
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: flushHeader=%d - CALLED!', intval($flushHeader)));
$this->rewind();
// And update seek position ...
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->updateSeekPosition() ...');
$this->updateSeekPosition();
- // ... to write it back into the file
- $this->flushFileHeader();
+ // Flush headers?
+ if ($flushHeader) {
+ // ... to write it back into the file
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
+ $this->flushFileHeader();
+ }
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
* @return void
*/
protected function seekToOldPosition () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
// Seek to currently ("old") saved position
- $this->seek($this->getSeekPosition());
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $this->seek($this->determineSeekPosition());
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Checks whether the block separator has been found
+ * Initializes this file class
*
- * @param $str String to look in
- * @return $isFound Whether the block separator has been found
+ * @param $fileInfoInstance An instance of a SplFileInfo class
+ * @return void
*/
- public static function isBlockSeparatorFound ($str) {
- // Determine it
- $isFound = (strpos($str, chr(self::SEPARATOR_ENTRIES)) !== false);
+ protected function initFile (SplFileInfo $fileInfoInstance) {
+ // Get a file i/o pointer instance
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: fileInfoInstance[%s]=%s - CALLED!', get_class($fileInfoInstance), $fileInfoInstance));
+ $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($fileInfoInstance));
- // Return result
- return $isFound;
+ // ... and set it here
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting pointerInstance=%s ...', $pointerInstance->__toString()));
+ $this->setPointerInstance($pointerInstance);
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Initializes the back-buffer by setting it to an empty string.
+ * Marks the currently loaded block as empty (with length of the block)
*
+ * @param $length Length of the block
* @return void
+ * @throws InvalidArgumentException If a parameter is invalid
*/
- private function initBackBuffer () {
- // Simply call the setter
- $this->setBackBuffer('');
+ protected function markCurrentBlockAsEmpty (int $length) {
+ // Validate parameter
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d - CALLED!', $length));
+ if ($length < 1) {
+ // Length cannot below one
+ throw new InvalidArgumentException(sprintf('length=%d is not valid', $length));
+ }
+
+ // Get current seek position
+ $currentPosition = $this->determineSeekPosition();
+
+ // Now add it as gap entry
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: currentPosition=%d', $currentPosition));
+ $this->addGap(($currentPosition - $length), $currentPosition);
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Setter for backBuffer field
+ * Initializes counter for valid entries, arrays for damaged entries and
+ * an array for gap seek positions. If you call this method on your own,
+ * please re-analyze the file structure. So you are better to call
+ * analyzeFileStructure() instead of this method.
*
- * @param $backBuffer Characters to "store" in back-buffer
* @return void
*/
- private function setBackBuffer ($backBuffer) {
- // Cast to string (so no arrays or objects)
- $backBuffer = (string) $backBuffer;
+ public function initCountersGapsArray () {
+ // Init counter and seek position to header size
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $this->setCounter(0);
+ $this->setSeekPosition($this->getHeaderSize());
- // ... and set it
- $this->backBuffer = $backBuffer;
- }
+ // Init arrays
+ $this->gaps = [];
+ $this->damagedEntries = [];
- /**
- * Getter for backBuffer field
- *
- * @return $backBuffer Characters "stored" in back-buffer
- */
- private function getBackBuffer () {
- return $this->backBuffer;
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Setter for currentBlock field
+ * Updates seekPosition attribute from file to avoid to much access on file.
*
- * @param $currentBlock Characters to set a currently loaded block
* @return void
*/
- private function setCurrentBlock ($currentBlock) {
- // Cast to string (so no arrays or objects)
- $currentBlock = (string) $currentBlock;
+ public function updateSeekPosition () {
+ // Get key (= seek position)
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $seekPosition = $this->determineSeekPosition();
- // ... and set it
- $this->currentBlock = $currentBlock;
- }
+ // And set it here
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d', $seekPosition));
+ $this->setSeekPosition($seekPosition);
- /**
- * Gets currently read data
- *
- * @return $current Currently read data
- */
- public function getCurrentBlock () {
- // Return it
- return $this->currentBlock;
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Initializes this file class
+ * Checks whether the block separator has been found
*
- * @param $infoInstance An instance of a SplFileInfo class
- * @return void
+ * @param $str String to look in
+ * @return $isFound Whether the block separator has been found
+ * @throws InvalidArgumentException If a parameter is not valid
*/
- protected function initFile (SplFileInfo $infoInstance) {
- // Get a file i/o pointer instance
- $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($infoInstance));
+ public static function isBlockSeparatorFound (string $str) {
+ // Validate parameter
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: str=%s - CALLED!', $str));
+ if (empty($str)) {
+ // Throw IAE
+ throw new InvalidArgumentException('Parameter "str" is empty');
+ }
- // ... and set it here
- $this->setPointerInstance($pointerInstance);
+ // Determine it
+ $isFound = (strpos($str, chr(self::SEPARATOR_ENTRIES)) !== false);
+
+ // Return result
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isFound=%d - EXIT!', intval($isFound)));
+ return $isFound;
}
/**
* @param $data Data to be written
* @param $flushHeader Whether to flush the header (default: flush)
* @return void
+ * @throws OutOfBoundsException If the position is not seekable
+ * @throws InvalidArgumentException If a parameter is invalid
*/
- public function writeData ($seekPosition, $data, $flushHeader = true) {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data()=%d - CALLED!', __METHOD__, __LINE__, $seekPosition, strlen($data)));
+ public function writeData (int $seekPosition, string $data, bool $flushHeader = true) {
+ // Validate parameter
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%s,data()=%d,flushHeader=%d - CALLED!', $seekPosition, strlen($data), intval($flushHeader)));
+ if ($seekPosition < 0) {
+ // Invalid seek position
+ throw new OutOfBoundsException(sprintf('seekPosition=%d is not valid', $seekPosition));
+ } elseif (empty($data)) {
+ // Empty data is invalid, too
+ throw new InvalidArgumentException('Parameter "data" is empty');
+ }
// Write data at given position
- $this->getPointerInstance()->writeAtPosition($seekPosition, $data);
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->writeAtPosition(%d,%s) ...', $seekPosition, $data));
+ $this->writeAtPosition($seekPosition, $data);
// Increment counter
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->incrementCounter() ...');
$this->incrementCounter();
// Update seek position
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->updateSeekPosition() ...');
$this->updateSeekPosition();
// Flush the header?
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: flushHeader=%d', intval($flushHeader)));
if ($flushHeader === true) {
// Flush header
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
$this->flushFileHeader();
// Seek to old position
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->seekToOldPosition() ...');
$this->seekToOldPosition();
- } // END - if
+ }
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Trace message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Marks the currently loaded block as empty (with length of the block)
+ * Writes at given position by seeking to it.
*
- * @param $length Length of the block
- * @return void
+ * @param $seekPosition Seek position in file
+ * @param $dataStream Data to be written
+ * @return mixed Number of writes bytes or false on error
+ * @throws OutOfBoundsException If the position is not seekable
+ * @throws InvalidArgumentException If a parameter is not valid
*/
- protected function markCurrentBlockAsEmpty ($length) {
- // Get current seek position
- $currentPosition = $this->key();
+ public function writeAtPosition (int $seekPosition, string $dataStream) {
+ // Validate parameter
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d,dataStream(%d)=%s - CALLED!', $seekPosition, strlen($dataStream), $dataStream));
+ if ($seekPosition < 0) {
+ // Invalid seek position
+ throw new OutOfBoundsException(sprintf('seekPosition=%d is not valid.', $seekPosition));
+ } elseif (empty($dataStream)) {
+ // Empty dataStream
+ throw new InvalidArgumentException('Parameter "dataStream" is empty');
+ }
- // Now add it as gap entry
- array_push($this->gaps, array(
- self::GAPS_INDEX_START => ($currentPosition - $length),
- self::GAPS_INDEX_END => $currentPosition,
- ));
+ // Call pointer's method
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->pointerInstance->writeAtPosition(%d, %s) ...', $seekPosition, $dataStream));
+ $status = $this->getPointerInstance()->writeAtPosition($seekPosition, $dataStream);
+
+ // Return status
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: status[%s]=%d - EXIT!', gettype($status), $status));
+ return $status;
}
/**
* @return $isInitialized Whether the file header is initialized
*/
public function isFileHeaderInitialized () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
// Default is not initialized
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
$isInitialized = false;
// Is the file initialized?
if ($this->isFileInitialized()) {
// Some bytes has been written, so rewind to start of it.
- $rewindStatus = $this->rewind();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
-
- // Is the rewind() call successfull?
- if ($rewindStatus != 1) {
- // Something bad happened
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Could not rewind().', __METHOD__, __LINE__));
- } // END - if
+ $this->rewind();
// Read file header
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->readFileHeader() ...');
$this->readFileHeader();
+ // Get header count
+ $headerCount = count($this->getHeader());
+
// The above method does already check the header
- $isInitialized = true;
- } // END - if
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: headerCount=%d', $headerCount));
+ $isInitialized = ($headerCount > 0);
+ }
// Return result
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isInitialized=%d - EXIT!', intval($isInitialized)));
return $isInitialized;
}
* Checks whether the assigned file has been initialized
*
* @return $isInitialized Whether the file's size is zero
+ * @throws UnexpectedValueException If an unexpected value was returned
*/
public function isFileInitialized () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
// Get it from iterator which holds the pointer instance. If false is returned
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
$fileSize = $this->size();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] fileSize=%s', __METHOD__, __LINE__, $fileSize));
/*
* The returned file size should not be false or NULL as this means
* that the pointer class does not work correctly.
*/
- assert(is_int($fileSize));
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: fileSize[%s]=%d', gettype($fileSize), $fileSize));
+ if (!is_int($fileSize)) {
+ // Bad file?
+ throw new UnexpectedValueException(sprintf('fileSize[]=%s is unexpected', gettype($fileSize)));
+ }
// Is more than 0 returned?
$isInitialized = ($fileSize > 0);
// Return result
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isInitialized=%d - EXIT!', intval($isInitialized)));
return $isInitialized;
}
* Creates the assigned file
*
* @return void
+ * @throws BadMethodCallException If this file's header is already initialized
*/
public function createFileHeader () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
// The file's header should not be initialized here
- assert(!$this->isFileHeaderInitialized());
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ if ($this->isFileHeaderInitialized()) {
+ // Bad method call
+ //* DEBUG-DIE: */ ApplicationEntryPoint::exitApplication(sprintf('[%s:%d]: this=%s', __METHOD__, __LINE__, print_r($this, TRUE)));
+ throw new BadMethodCallException('File header is already initialized but method called');
+ }
// Simple flush file header which will create it.
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
$this->flushFileHeader();
// Rewind seek position (to beginning of file) and update/flush file header
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->rewindUpdateSeekPosition() ...');
$this->rewindUpdateSeekPosition();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
*
* @param $type Type of the file
* @return void
+ * @throws InvalidArgumentException If a parameter is empty
*/
- public function preAllocateFile ($type) {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
+ public function preAllocateFile (string $type) {
// Is it enabled?
- if ($this->getConfigInstance()->getConfigEntry($type . '_pre_allocate_enabled') != 'Y') {
- // Not enabled
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Not pre-allocating file.', __METHOD__, __LINE__));
-
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: type=%s - CALLED!', $type));
+ if (empty($type)) {
+ // Empty type
+ throw new InvalidArgumentException('Parameter "type" is empty');
+ } elseif (FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_enabled') != 'Y') {
// Don't continue here.
+ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Not pre-allocating file.'));
return;
- } // END - if
+ }
// Message to user
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Pre-allocating file ...', __METHOD__, __LINE__));
+ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Pre-allocating file ...');
- // Calculate minimum length for one entry
- $minLengthEntry = $this->getBlockInstance()->calculateMinimumBlockLength();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] minLengthEntry=%s', __METHOD__, __LINE__, $minLengthEntry));
+ // Calculate minimum length for one entry and get file size
+ $minimumBlockLength = $this->getIndexInstance()->calculateMinimumBlockLength();
+ $fileSize = $this->getFileSize();
// Calulcate seek position
- $seekPosition = $minLengthEntry * $this->getConfigInstance()->getConfigEntry($type . '_pre_allocate_count');
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: minimumBlockLength=%d,fileSize=%d', $minimumBlockLength, $fileSize));
+ $seekPosition = $minimumBlockLength * FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_count') + $fileSize ;
// Now simply write a NUL there. This will pre-allocate the file.
- $this->writeData($seekPosition, chr(0));
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->writeAtPosition(%d,NUL) ...', $seekPosition));
+ $this->writeAtPosition($seekPosition, chr(0));
+
+ // Is the seek position zero?
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: fileSize=%d', $fileSize));
+ if ($fileSize == 0) {
+ // Mark file as gaps-only
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->markGapsOnly(%s,%d) ...', $type, $minimumBlockLength));
+ $this->markFileGapsOnly($type, $minimumBlockLength);
+ } else {
+ // Analyze file structure
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->analyzeFileStructure() ...');
+ $this->analyzeFileStructure();
+ }
- // Rewind seek position (to beginning of file) and update/flush file header
- $this->rewindUpdateSeekPosition();
+ // Rewind seek position
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->rewind() ...');
+ $this->rewind();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
*/
public function determineSeekPosition () {
// Call pointer instance
- return $this->getPointerInstance()->determineSeekPosition();
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $seekPosition = $this->getPointerInstance()->determineSeekPosition();
+
+ // Return position
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d - EXIT!', $seekPosition));
+ return $seekPosition;
}
/**
* @param $offset Offset to seek to (or used as "base" for other seeks)
* @param $whence Added to offset (default: only use offset to seek to)
* @return $status Status of file seek: 0 = success, -1 = failed
+ * @throws OutOfBoundsException If the position is not seekable
*/
- public function seek ($offset, $whence = SEEK_SET) {
+ public function seek (int $offset, int $whence = SEEK_SET) {
+ // Validate parameter
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: offset=%d,whence=%d - CALLED!', $offset, $whence));
+ if ($offset < 0) {
+ // No offset is smaller than zero
+ throw new OutOfBoundsException(sprintf('offset=%d is not valid', $offset));
+ }
+
// Call pointer instance
- return $this->getPointerInstance()->seek($offset, $whence);
+ $status = $this->getPointerInstance()->seek($offset, $whence);
+
+ // Return status
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: status[%s]=%d - EXIT!', gettype($status), $status));
+ return $status;
}
/**
*
* @param $bytes Amount of bytes to read
* @return $data Data read from file
+ * @throws OutOfBoundsException If the position is not seekable
*/
- public function read ($bytes = NULL) {
- // $bytes shall be integer
- assert(is_int($bytes));
+ public function read (int $bytes = 0) {
+ // Validate parameter
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: bytes=%d - CALLED!', $bytes));
+ if ($bytes < 0) {
+ // Throw exception
+ throw new OutOfBoundsException(sprintf('bytes=%d is not valid', $bytes));
+ }
// Call pointer instance
- return $this->getPointerInstance()->read($bytes);
+ $data = $this->getPointerInstance()->read($bytes);
+
+ // Return data
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data[%s]=%s - EXIT!', gettype($data), $data));
+ return $data;
}
/**
* Rewinds to the beginning of the file
*
- * @return $status Status of this operation
+ * @return void
*/
public function rewind () {
// Call pointer instance
- return $this->getPointerInstance()->rewind();
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $this->getPointerInstance()->rewind();
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
* only gaps are found, the file is considered as "virgin" (no entries).
*
* @return void
+ * @throws BadMethodCallException If this method is called but file is not initialized
*/
- public function analyzeFile () {
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
-
+ public function analyzeFileStructure () {
// Make sure the file is initialized
- assert($this->isFileInitialized());
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ if (!$this->isFileInitialized()) {
+ // Bad method call
+ throw new BadMethodCallException('Method called but file is not initialized.');
+ }
// Init counters and gaps array
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->initCounterGapsArrays() ...');
$this->initCountersGapsArray();
// Output message (as this may take some time)
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Analyzing file structure ... (this may take some time)', __METHOD__, __LINE__));
+ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('Analyzing file structure ... (this may take some time)'));
// First rewind to the begining
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->rewind() ...');
$this->rewind();
// Then try to load all entries
- while ($this->valid()) {
- // Go to next entry
- $this->next();
-
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Looping through file');
+ while ($this->isValid()) {
// Get current entry
$current = $this->getCurrentBlock();
+ // Go to next entry
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->readNextBlock() ...');
+ $this->readNextBlock();
+
/*
* If the block is empty, maybe the whole file is? This could mean
* that the file has been pre-allocated.
*/
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current(%d)[]=%s', strlen($current), gettype($current)));
if (empty($current)) {
// Then skip this part
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current[]=%s is empty - CONTINUE!', gettype($current)));
continue;
- } // END - if
+ }
- // Debug message
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] current()=%d', __METHOD__, __LINE__, strlen($current)));
- } // END - while
+ // Handle current record
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current(%d)[]=%s', strlen($current), gettype($current)));
+ }
// If the last read block is empty, check gaps
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current()=%d', strlen($current)));
if (empty($current)) {
// Output message
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Found a total of %s gaps.', __METHOD__, __LINE__, count($this->gaps)));
+ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Found a total of %d gaps.', count($this->gaps)));
// Check gaps, if the whole file is empty.
- if ($this->isFileOnlyGaps()) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->isFileGapsOnly() ...');
+ if ($this->isFileGapsOnly()) {
// Only gaps, so don't continue here.
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: File is gaps-only - EXIT!');
return;
- } // END - if
+ }
/*
* The above call has calculated a total size of all gaps. If the
* defragmentation is to far in the past, or if a "hard" limit has
* reached, run defragmentation.
*/
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->isDefragmentationNeeded() ...');
if ($this->isDefragmentationNeeded()) {
// Run "defragmentation"
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->doRunDefragmentation() ...');
$this->doRunDefragmentation();
- } // END - if
- } // END - if
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
+ }
+ }
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
- * Advances to next "block" of bytes
+ * Reads next "block" of bytes into $currentBlock field
*
* @return void
+ * @throws BadMethodCallException If this method was called without prior valid() call
*/
- public function next () {
+ public function readNextBlock () {
// Is there nothing to read?
- if (!$this->valid()) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ if (!$this->isValid()) {
// Nothing to read
- return;
- } // END - if
-
- // Debug message
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d] key()=%d', __FUNCTION__, __LINE__, $this->key()));
-
- // Make sure the block instance is set
- assert($this->getBlockInstance() instanceof CalculatableBlock);
+ throw new BadMethodCallException('next() invoked but no valid current block (EOF?)');
+ }
// First calculate minimum block length
- $length = $this->getBlockInstance()->calculateMinimumBlockLength();
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d] length=%s', __FUNCTION__, __LINE__, $length));
-
- // Short be more than zero!
- assert($length > 0);
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: this->seekPosition=%d', $this->determineSeekPosition()));
+ $length = $this->getIndexInstance()->calculateMinimumBlockLength();
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d', $length));
// Read possibly back-buffered bytes from previous call of next().
$data = $this->getBackBuffer();
* "block" may not fit, so this loop will continue until the EOB or EOF
* has been reached whatever comes first.
*/
- while ((!$this->isEndOfFileReached()) && (!self::isBlockSeparatorFound($data))) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data()=%d', strlen($data)));
+ while ((!$this->isEndOfFileReached()) && (empty($data) || !self::isBlockSeparatorFound($data))) {
// Then read the next possible block
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->read(%d) ...', $length));
$block = $this->read($length);
- // Debug message
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d] block()=%d,length=%s', __FUNCTION__, __LINE__, strlen($block), $length));
-
// Is it all empty?
- if (strlen(trim($block)) == 0) {
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: block()=%d,length=%d', strlen($block), $length));
+ if (strlen(trim($block, chr(0))) == 0) {
// Mark this block as empty
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->markCurrentBlockAsEmpty(%d) ...', strlen($block)));
$this->markCurrentBlockAsEmpty(strlen($block));
- // Skip to next block
- continue;
- } // END - if
+ // Exit look
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Empty block found ... - BREAK!');
+ break;
+ }
// At this block then
$data .= $block;
// A debug message
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d] data()=%d', __FUNCTION__, __LINE__, strlen($data)));
- } // END - while
-
- // EOF reached?
- if ($this->isEndOfFileReached()) {
- // Set whole data as current read block
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('Calling setCurrentBlock(' . strlen($data) . ') ...');
- $this->setCurrentBlock($data);
-
- // Then abort here silently
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('EOF reached.');
- return;
- } // END - if
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data(%d)=%s', strlen($data), $data));
+ }
/*
* Init back-buffer which is the data that has been found beyond the
*/
$this->initBackBuffer();
+ // Is $data empty?
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data(%d)=%s', strlen($data), $data));
+ if (empty($data)) {
+ // Yes, maybe whole file was ...
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Maybe empty file found - EXIT!');
+ return;
+ }
+
// Separate data
$dataArray = explode(chr(self::SEPARATOR_ENTRIES), $data);
- // This array must contain two elements
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('dataArray=' . print_r($dataArray, true));
- assert(count($dataArray) == 2);
-
- // Left part is the actual block, right one the back-buffer data
+ // Left part is the actual block, right one the back-buffer data, if found
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: dataArray()=%d', count($dataArray)));
+ //* PRINTR-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: dataArray=%s', print_r($dataArray, true)));
$this->setCurrentBlock($dataArray[0]);
- $this->setBackBuffer($dataArray[1]);
+
+ // Is back buffere data found?
+ if (isset($dataArray[1])) {
+ // Set back buffer
+ $this->setBackBuffer($dataArray[1]);
+ }
+
+ // Trace message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
* This method will return true if an emptied (nulled) entry has been found.
*
* @return $isValid Whether the next entry is valid
+ * @throws UnexpectedValueException If some value is not expected
*/
- public function valid () {
- // Make sure the block instance is set
- assert($this->getBlockInstance() instanceof Block);
-
+ public function isValid () {
// First calculate minimum block length
- $length = $this->getBlockInstance()->calculateMinimumBlockLength();
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $length = $this->getIndexInstance()->calculateMinimumBlockLength();
// Short be more than zero!
- assert($length > 0);
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d', $length));
+ if ($length < 1) {
+ // Throw UVE
+ throw new UnexpectedValueException(sprintf('length=%d is not expected', $length));
+ }
// Get current seek position
- $seekPosition = $this->key();
+ $seekPosition = $this->determineSeekPosition();
// Then try to read it
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d', $seekPosition));
$data = $this->read($length);
// If some bytes could be read, all is fine
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data[%s]()=%d', gettype($data), strlen($data)));
$isValid = ((is_string($data)) && (strlen($data) > 0));
// Get header size
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isValid=%d', intval($isValid)));
$headerSize = $this->getHeaderSize();
// Is the seek position at or beyond the header?
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d,headerSize=%d', $seekPosition, $headerSize));
if ($seekPosition >= $headerSize) {
// Seek back to old position
- $this->seek($seekPosition);
+ $isValid = ($isValid && $this->seek($seekPosition) === 0);
} else {
// Seek directly behind the header
- $this->seek($headerSize);
+ $isValid = ($isValid && $this->seek($headerSize) === 0);
}
// Return result
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isValid=%d - EXIT!', intval($isValid)));
return $isValid;
}
- /**
- * Gets current seek position ("key").
- *
- * @return $key Current key in iteration
- */
- public function key () {
- // Call pointer instance
- return $this->getPointerInstance()->determineSeekPosition();
- }
-
/**
* Reads the file header
*
* @return void
+ * @throws LogicException If both instances are not set
*/
public function readFileHeader () {
- // Make sure the block instance is set
- assert($this->getBlockInstance() instanceof Block);
+ // Is index set or stack?
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ if ($this->getIndexInstance() instanceof Indexable) {
+ // Call index instance
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->indexInstance->readIndexHeader() ...');
+ $this->getIndexInstance()->readIndexHeader();
+ } elseif ($this->getStackInstance() instanceof StackableFile) {
+ // Call stacke instance
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->stackInstance->readStackHeader() ...');
+ $this->getStackInstance()->readStackHeader();
+ } else {
+ // Bad logic?
+ throw new LogicException('Wether indexInstance nor stackInstance are set');
+ }
- // Call block instance
- $this->getBlockInstance()->readFileHeader();
+ // Trace message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
* @return void
*/
public function flushFileHeader () {
- // Make sure the block instance is set
- assert($this->getBlockInstance() instanceof Block);
-
// Call block instance
- $this->getBlockInstance()->flushFileHeader();
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
+ $this->getIndexInstance()->flushFileHeader();
+
+ // Trace message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
}
/**
*
* @param $length Length of raw data
* @return $seekPosition Found next gap's seek position
+ * @throws InvalidArgumentException If the parameter is not valid
*/
- public function searchNextGap ($length) {
+ public function searchNextGap (int $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
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d - CALLED!', $length));
+ if ($length <= 0) {
+ // Throw IAE
+ throw new InvalidArgumentException(sprintf('length=%d is not valid', $length));
+ } elseif ($this->isFileGapsOnly()) {
+ /*
+ * The first empty block is the 2nd one right after the header, so
+ * one byte gap to the header.
+ */
+ $seekPosition = ($this->getHeaderSize() + 2);
+
+ // Return position
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d - EXIT!', $seekPosition));
+ return $seekPosition;
+ }
// @TODO Unfinished
$this->partialStub('length=' . $length);