X-Git-Url: https://git.mxchange.org/?p=core.git;a=blobdiff_plain;f=framework%2Fmain%2Fclasses%2Ffile_directories%2Fio_stream%2Fclass_FileIoStream.php;h=7bb7b2993dc92bfc90399aa2cf186f73448e4082;hp=ae0f6352a8ba6ada1e392c0d850165eda510e680;hb=refs%2Fheads%2Fmaster;hpb=a60894f1d6ef33613d2d0351075aa07aa257f304 diff --git a/framework/main/classes/file_directories/io_stream/class_FileIoStream.php b/framework/main/classes/file_directories/io_stream/class_FileIoStream.php index ae0f6352..9a82005c 100644 --- a/framework/main/classes/file_directories/io_stream/class_FileIoStream.php +++ b/framework/main/classes/file_directories/io_stream/class_FileIoStream.php @@ -4,14 +4,18 @@ namespace Org\Mxchange\CoreFramework\Stream\Filesystem; // Import framework stuff use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint; -use Org\Mxchange\CoreFramework\Factory\ObjectFactory; +use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory; use Org\Mxchange\CoreFramework\Filesystem\FileNotFoundException; +use Org\Mxchange\CoreFramework\Generic\FrameworkInterface; use Org\Mxchange\CoreFramework\Generic\UnsupportedOperationException; +use Org\Mxchange\CoreFramework\Middleware\Debug\DebugMiddleware; use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem; use Org\Mxchange\CoreFramework\Stream\Filesystem\FileInputStreamer; use Org\Mxchange\CoreFramework\Stream\Filesystem\FileOutputStreamer; // Import SPL stuff +use \InvalidArgumentException; +use \OutOfBoundsException; use \SplFileInfo; /** @@ -19,7 +23,7 @@ use \SplFileInfo; * * @author Roland Haeder * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team * @license GNU GPL 3.0 or any newer version * @link http://www.shipsimu.org * @@ -60,7 +64,7 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil /** * Protected constructor */ - protected function __construct () { + private function __construct () { // Call parent constructor parent::__construct(__CLASS__); } @@ -73,9 +77,11 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil */ public static final function createFileIoStream () { // Create new instance + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('FILE-IO-STREAM: CALLED!'); $ioInstance = new FileIoStream(); // Return the instance + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: ioInstance=%s - EXIT!', $ioInstance->__toString())); return $ioInstance; } @@ -86,24 +92,33 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil * @param $dataArray The data we shall store to the file * @return void * @see FileOutputStreamer - * @todo This method needs heavy rewrite + * @throws InvalidArgumentException If an invalid parameter was given + * @throws OutOfBoundsException If an expected array element wasn't found */ public final function saveFile (SplFileInfo $fileInfoInstance, array $dataArray) { - // Try it five times - $dirName = ''; - $fileInstance = NULL; - - for ($idx = 0; $idx < 5; $idx++) { + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: fileInfoInstance=%s,dataArray()=%d - CALLED!', $fileInfoInstance, count($dataArray))); + if (count($dataArray) < 2) { + // Not valid array, at least 2 elements must be there! + throw new InvalidArgumentException(sprintf('Parameter "dataArray" should have at least 2 elements, has %d', count($dataArray))); + } else if (!isset($dataArray[0])) { + // Array element 0 not found + throw new OutOfBoundsException(sprintf('Array element dataArray[0] not found, dataArray=%s', json_encode($dataArray))); + } else if (!isset($dataArray[1])) { + // Array element 1 not found + throw new OutOfBoundsException(sprintf('Array element dataArray[1] not found, dataArray=%s', json_encode($dataArray))); + } + + try { // Get a file output pointer - try { - $fileInstance = ObjectFactory::createObjectByConfiguredName('file_raw_output_class', array($fileInfoInstance, 'wb')); - } catch (FileNotFoundException $e) { - // Bail out - ApplicationEntryPoint::exitApplication('The application has made a fatal error. Exception: ' . $e->__toString() . ' with message: ' . $e->getMessage()); - } - } // END - for + $fileInstance = ObjectFactory::createObjectByConfiguredName('file_raw_output_class', [$fileInfoInstance, 'wb']); + } catch (FileNotFoundException $e) { + // Bail out + ApplicationEntryPoint::exitApplication('The application has made a fatal error. Exception: ' . $e->__toString() . ' with message: ' . $e->getMessage()); + } // Write a header information for validation purposes + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Writing header to fileInstance=%s ...', $fileInstance->__toString())); $fileInstance->writeToFile(sprintf('%s%s%s%s%s%s%s%s%s' . PHP_EOL, self::FILE_IO_FILE_HEADER_ID, self::FILE_IO_SEPARATOR, @@ -117,15 +132,17 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil )); // Encode the (maybe) binary stream with Base64 + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Encoding %d bytes to BASE64 string ...', strlen($dataArray[1]))); $b64Stream = base64_encode($dataArray[1]); - // write the data line by line + // write the data line-by-line $line = str_repeat(' ', 50); $idx = 0; while (strlen($line) == 50) { // Get 50 chars or less $line = substr($b64Stream, $idx, 50); // Save it to the stream + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Writing %d bytes to file ...', strlen($line))); $fileInstance->writeToFile(sprintf('%s%s%s%s%s' . PHP_EOL, self::FILE_IO_DATA_BLOCK_ID, self::FILE_IO_SEPARATOR, @@ -136,10 +153,14 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil // Advance to the next 50-chars block $idx += 50; - } // END - while + } // Close the file + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage('FILE-IO-STREAM: Closing file ...'); unset($fileInstance); + + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('FILE-IO-STREAM: EXIT!'); } /** @@ -151,113 +172,142 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil */ public final function loadFileContents (SplFileInfo $infoInstance) { // Initialize some variables and arrays + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: infoInstance=%s - CALLED!', $infoInstance)); $inputBuffer = ''; $lastBuffer = ''; - $header = array(); - $data = array(); + $header = []; + $data = []; $readData = ''; // This will contain our read data // Get a file input handler $fileInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_class', array($infoInstance)); // Read all it's contents (we very and transparently decompress it below) + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: fileInstance=%s', $fileInstance->__toString())); while ($readRawLine = $fileInstance->readFromFile()) { // Add the read line to the buffer + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Adding %d read bytes to input buffer.', strlen($readRawLine))); $inputBuffer .= $readRawLine; // Break infinite loop maybe caused by the input handler if ($lastBuffer == $inputBuffer) { + // Break out of loop, EOF reached? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage('FILE-IO-STREAM: EOF reached!'); break; - } // END - if + } // Remember last read line for avoiding possible infinite loops $lastBuffer = $inputBuffer; - } // END - while + } // Close directory handle + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage('FILE-IO-STREAM: Closing file ...'); unset($fileInstance); // Convert it into an array - $inputBuffer = explode(chr(10), $inputBuffer); + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Read inputBuffer=%d bytes from infoInstance=%s', strlen($inputBuffer), $infoInstance)); + $inputArray = explode(chr(10), $inputBuffer); // Now process the read lines and verify it's content - foreach ($inputBuffer as $rawLine) { + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: inputArray()=%d', count($inputArray))); + foreach ($inputArray as $rawLine) { // Trim it a little but not the leading spaces/tab-stops $rawLine = rtrim($rawLine); // Analyze this line + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: rawLine()=%d', strlen($rawLine))); if (substr($rawLine, 0, 5) == self::FILE_IO_FILE_HEADER_ID) { // Header found, so let's extract it + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Found header, rawLine=%s', $rawLine)); $header = explode(self::FILE_IO_SEPARATOR, $rawLine); - $header = trim($header[1]); + $headerLine = trim($header[1]); // Now we must convert it again into an array - $header = explode(self::FILE_IO_CHUNKER, $header); + $header = explode(self::FILE_IO_CHUNKER, $headerLine); // Is the header (maybe) valid? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: header()=%d', count($header))); if (count($header) != 4) { // Throw an exception - throw new InvalidArrayCountException(array($this, 'header', count($header), 4), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); - } // END - if + throw new InvalidArrayCountException([$this, 'header', count($header), 4], self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); + } } elseif (substr($rawLine, 0, 5) == self::FILE_IO_DATA_BLOCK_ID) { // Is a data line! + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Data line found rawLine=%s', $rawLine)); $data = explode(self::FILE_IO_SEPARATOR, $rawLine); - $data = $data[1]; + $dataLine = $data[1]; // First element is the data, second the MD5 checksum - $data = explode(self::FILE_IO_CHUNKER, $data); + $data = explode(self::FILE_IO_CHUNKER, $dataLine); // Validate the read line + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: data()=%d', count($data))); if (count($data) == 2) { - if (md5($data[0]) != $data[1]) { + // Generate checksum (MD5 is okay here) + $checksum = md5($data[0]); + + // Check if it matches provided one + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: checksum=%s,data[1]=%s', $checksum, $data[1])); + if ($checksum != $data[1]) { // MD5 hash did not match! - throw new InvalidMD5ChecksumException(array($this, md5($data[0]), $data[1]), self::EXCEPTION_MD5_CHECKSUMS_MISMATCH); - } // END - if + throw new InvalidMD5ChecksumException([$this, $checksum, $data[1]], self::EXCEPTION_MD5_CHECKSUMS_MISMATCH); + } } else { // Invalid count! - throw new InvalidArrayCountException(array($this, 'data', count($data), 2), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); + throw new InvalidArrayCountException([$this, 'data', count($data), 2], self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); } // Add this to the readData string + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Adding %d raw data to input stream', strlen($data[0]))); $readData .= $data[0]; } else { // Other raw lines than header/data tagged lines and re-add the new-line char + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: Adding rawLine=%s(%d) + PHP_EOL to input stream', $rawLine, strlen($rawLine))); $readData .= $rawLine . PHP_EOL; } - } // END - foreach + } // Was raw lines read and no header/data? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: readData()=%d,header()=%d,data()=%d', strlen($readData), count($header), count($data))); if ((!empty($readData)) && (count($header) == 0) && (count($data) == 0)) { // Return raw lines back + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: readData()=%d - EXIT!', strlen($readData))); return $readData; - } // END - if + } // Was a header found? + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: header()=%d', count($header))); if (count($header) != 4) { // Throw an exception - throw new InvalidArrayCountException(array($this, 'header', count($header), 4), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); - } // END - if + throw new InvalidArrayCountException([$this, 'header', count($header), 4], self::EXCEPTION_ARRAY_HAS_INVALID_COUNT); + } // Decode all from Base64 - $readData = @base64_decode($readData); + $decodedData = @base64_decode($readData); // Does the size match? - if (strlen($readData) != $header[2]) { + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: decodedData()=%d,header[2]=%d', strlen($decodedData), $header[2])); + if (strlen($decodedData) != $header[2]) { // Size did not match - throw new InvalidDataLengthException(array($this, strlen($readData), $header[2]), self::EXCEPTION_UNEXPECTED_STRING_SIZE); - } // END - if + throw new InvalidDataLengthException([$this, strlen($decodedData), $header[2]], self::EXCEPTION_UNEXPECTED_STRING_SIZE); + } + + // Generate checksum from whole read data + $checksum = md5($decodedData); // Validate the decoded data with the final MD5 hash - if (md5($readData) != $header[3]) { + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('FILE-IO-STREAM: checksum=%s,header[3]=%s', $checksum, $header[3])); + if ($checksum != $header[3]) { // MD5 hash did not match! - throw new InvalidMD5ChecksumException(array($this, md5($readData), $header[3]), self::EXCEPTION_MD5_CHECKSUMS_MISMATCH); - } // END - if + throw new InvalidMD5ChecksumException([$this, $checksum, $header[3]], self::EXCEPTION_MD5_CHECKSUMS_MISMATCH); + } // Return all in an array - return array( + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: header()=%d,decodedData()=%d - EXIT!', count($header), strlen($decodedData))); + return [ 'header' => $header, - 'data' => $readData - ); + 'data' => $decodedData, + ]; } /** @@ -267,9 +317,10 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil * @return $data The data (string mostly) to "stream" * @throws UnsupportedOperationException If this method is called */ - public function streamData ($data) { - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('Unhandled ' . strlen($data) . ' bytes in this stream.'); - throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION); + public function streamData (string $data) { + // Not supported + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: data=()=%d - CALLED!', strlen($data))); + throw new UnsupportedOperationException([$this, __FUNCTION__], FrameworkInterface::EXCEPTION_UNSPPORTED_OPERATION); } /** @@ -279,7 +330,9 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil * @todo 0% done */ public function determineSeekPosition () { - $this->partialStub(); + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('FILE-IO-STREAM: CALLED!'); + DebugMiddleware::getSelfInstance()->partialStub(); } /** @@ -289,8 +342,18 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil * @param $whence Added to offset (default: only use offset to seek to) * @return $status Status of file seek: 0 = success, -1 = failed */ - public function seek ($offset, $whence = SEEK_SET) { - $this->partialStub('offset=' . $offset . ',whence=' . $whence); + public function seek (int $offset, int $whence = SEEK_SET) { + // Check parameters + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('FILE-IO-STREAM: offset=%d,whence=%d - CALLED!', $offset, $whence)); + if ($offset < 0) { + // Throw IAE + throw new InvalidArgumentException(sprintf('offset=%d is below zero', $offset), FrameworkInterface::EXCEPTION_INVALID_ARGUMENT); + } elseif ($whence < 0) { + // Throw IAE + throw new InvalidArgumentException(sprintf('whence=%d is below zero', $whence), FrameworkInterface::EXCEPTION_INVALID_ARGUMENT); + } + + DebugMiddleware::getSelfInstance()->partialStub('offset=' . $offset . ',whence=' . $whence); } /** @@ -299,7 +362,9 @@ class FileIoStream extends BaseFrameworkSystem implements FileInputStreamer, Fil * @return $size Size (in bytes) of file */ public function size () { - $this->partialStub(); + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('FILE-IO-STREAM: CALLED!'); + DebugMiddleware::getSelfInstance()->partialStub(); } }