Continued:
[core.git] / framework / main / classes / file_directories / io_stream / class_FileIoStream.php
index ae0f6352a8ba6ada1e392c0d850165eda510e680..9a82005ca9669aa738187231a6b1e0066054162e 100644 (file)
@@ -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 <webmaster@shipsimu.org>
  * @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();
        }
 
 }