]> git.mxchange.org Git - core.git/blob - framework/main/classes/file_directories/io/class_FrameworkFileInputOutputPointer.php
Refacuring / possible WIP:
[core.git] / framework / main / classes / file_directories / io / class_FrameworkFileInputOutputPointer.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Filesystem\Pointer;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Filesystem\BaseFileIo;
8 use Org\Mxchange\CoreFramework\Filesystem\FileReadProtectedException;
9 use Org\Mxchange\CoreFramework\Filesystem\FileWriteProtectedException;
10 use Org\Mxchange\CoreFramework\Filesystem\PathWriteProtectedException;
11 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
12 use Org\Mxchange\CoreFramework\Generic\UnsupportedOperationException;
13 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
14
15 // Import SPL stuff
16 use \InvalidArgumentException;
17 use \SplFileInfo;
18 use \OutOfBoundsException;
19 use \UnexpectedValueException;
20
21 /**
22  * A class for reading files
23  *
24  * @author              Roland Haeder <webmaster@shipsimu.org>
25  * @version             0.0.0
26  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
27  * @license             GNU GPL 3.0 or any newer version
28  * @link                http://www.shipsimu.org
29  *
30  * This program is free software: you can redistribute it and/or modify
31  * it under the terms of the GNU General Public License as published by
32  * the Free Software Foundation, either version 3 of the License, or
33  * (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License
41  * along with this program. If not, see <http://www.gnu.org/licenses/>.
42  */
43 class FrameworkFileInputOutputPointer extends BaseFileIo implements InputOutputPointer {
44         /**
45          * Protected constructor
46          *
47          * @return      void
48          */
49         protected function __construct () {
50                 // Call parent constructor
51                 parent::__construct(__CLASS__);
52         }
53
54         /**
55          * Create a file pointer based on the given file. The file will also
56          * be verified here.
57          *
58          * @param       $fileInstance   An instance of a SplFileInfo class
59          * @return      void
60          * @throws      FileReadProtectedException      If PHP cannot read an existing file
61          * @throws      FileWriteProtectedException     If PHP cannot write an existing file
62          * @throws      PathWriteProtectedException     If PHP cannot write to an existing path
63          * @throws      FileIoException                         If fopen() returns not a file resource
64          */
65         public static final function createFrameworkFileInputOutputPointer (SplFileInfo $fileInstance) {
66                 // Some pre-sanity checks...
67                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: fileInstance[%s]=%s - CALLED!', get_class($fileInstance), $fileInstance));
68                 if (!FrameworkBootstrap::isReachableFilePath($fileInstance)) {
69                         // File exists but cannot be read
70                         throw new FileIoException($fileInstance, self::EXCEPTION_FILE_NOT_REACHABLE);
71                 } elseif ((!FrameworkBootstrap::isReadableFile($fileInstance)) && (file_exists($fileInstance))) {
72                         // File exists but cannot be read
73                         throw new FileReadProtectedException($fileInstance, self::EXCEPTION_FILE_CANNOT_BE_READ);
74                 } elseif (!is_writable($fileInstance->getPath())) {
75                         // Path is not writable
76                         throw new PathWriteProtectedException($fileInstance, self::EXCEPTION_PATH_CANNOT_BE_WRITTEN);
77                 } elseif (($fileInstance->isFile()) && (!$fileInstance->isWritable())) {
78                         // File exists but cannot be written
79                         throw new FileWriteProtectedException($fileInstance, self::EXCEPTION_FILE_CANNOT_BE_WRITTEN);
80                 }
81
82                 // Try to open a handler
83                 $fileObject = $fileInstance->openFile('c+b');
84
85                 // Is it valid?
86                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: fileObject[]=%s', gettype($fileObject)));
87                 if ((is_null($fileObject)) || ($fileObject === false)) {
88                         // Something bad happend
89                         throw new FileIoException($fileInstance->getPathname(), self::EXCEPTION_FILE_POINTER_INVALID);
90                 }
91
92                 // Create new instance
93                 $pointerInstance = new FrameworkFileInputOutputPointer();
94
95                 // Set file object and file name
96                 $pointerInstance->setFileObject($fileObject);
97
98                 // Return the instance
99                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: pointerInstance=%s - EXIT!', $pointerInstance->__toString()));
100                 return $pointerInstance;
101         }
102
103         /**
104          * Read 1024 bytes data from a file pointer
105          *
106          * @return      mixed   The result of fread()
107          */
108         public function readFromFile () {
109                 // Read data from the file pointer and return it
110                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('FILE-INPUT-OUTPUT-POINTER: CALLED!');
111                 $data = $this->read(1024);
112
113                 // Return data
114                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: data[%s]=%d - EXIT!', gettype($data), $data));
115                 return $data;
116         }
117
118         /**
119          * Write data to a file pointer
120          *
121          * @param       $dataStream             The data stream we shall write to the file
122          * @return      mixed                   Number of writes bytes or false on error
123          */
124         public function writeToFile (string $dataStream) {
125                 // Validate parameter
126                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: dataStream(%d)=%s - CALLED!', strlen($dataStream), $dataStream));
127                 if (empty($dataStream)) {
128                         // Empty dataStream
129                         throw new InvalidArgumentException('Parameter "dataStream" is empty');
130                 }
131
132                 // Get length
133                 $length = strlen($dataStream);
134
135                 // Write data to the file pointer and return written bytes
136                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: Calling this->fileObject->fwrite(%s,%d) ...', $dataStream, $length));
137                 $status = $this->getFileObject()->fwrite($dataStream, $length);
138
139                 // Return status
140                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: status[%s]=%d - EXIT!', gettype($status), $status));
141                 return $status;
142         }
143
144         /**
145          * Writes at given position by seeking to it.
146          *
147          * @param       $seekPosition   Seek position in file
148          * @param       $dataStream             Data to be written
149          * @return      mixed                   Number of writes bytes or false on error
150          * @throws      OutOfBoundsException    If the position is not seekable
151          * @throws      InvalidArgumentException        If a parameter is not valid
152          */
153         public function writeAtPosition (int $seekPosition, string $dataStream) {
154                 // Validate parameter
155                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: seekPosition=%d,dataStream(%d)=%s - CALLED!', $seekPosition, strlen($dataStream), $dataStream));
156                 if ($seekPosition < 0) {
157                         // Invalid seek position
158                         throw new OutOfBoundsException(sprintf('seekPosition=%d is not valid.', $seekPosition));
159                 } elseif (empty($dataStream)) {
160                         // Empty dataStream
161                         throw new InvalidArgumentException('Parameter "dataStream" is empty');
162                 } elseif (($this->getFileSize() > 0 || $seekPosition > 0) && $this->seek($seekPosition) === -1) {
163                         // Could not seek
164                         throw new InvalidArgumentException(sprintf('Could not seek to seekPosition=%d', $seekPosition));
165                 }
166
167                 // Then write the data at that position
168                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: Calling this->writeToFile(%s) ...', $dataStream));
169                 $status = $this->writeToFile($dataStream);
170
171                 // Return status
172                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: status[%s]=%d - EXIT!', gettype($status), $status));
173                 return $status;
174         }
175
176         /**
177          * Rewinds to the beginning of the file
178          *
179          * @return      void
180          */
181         public function rewind () {
182                 /// Rewind the pointer
183                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('FILE-INPUT-OUTPUT-POINTER: CALLED!');
184                 $this->getFileObject()->rewind();
185
186                 // Trace message
187                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('FILE-INPUT-OUTPUT-POINTER: EXIT!');
188         }
189
190         /**
191          * Seeks to given position
192          *
193          * @param       $seekPosition   Seek position in file
194          * @param       $whence                 "Seek mode" (see http://de.php.net/fseek)
195          * @return      $status                 Status of this operation
196          * @throws      OutOfBoundsException    If the position is not seekable
197          */
198         public function seek (int $seekPosition, int $whence = SEEK_SET) {
199                 // Validate parameter
200                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: seekPosition=%d,whence=%d - CALLED!', $seekPosition, $whence));
201                 if ($seekPosition < 0) {
202                         // Invalid seek position
203                         throw new OutOfBoundsException(sprintf('seekPosition=%d is not valid.', $seekPosition));
204                 }
205
206                 // Move the file pointer
207                 $status = $this->getFileObject()->fseek($seekPosition, $whence);
208
209                 // Return status
210                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: status[%s]=%d - EXIT!', gettype($status), $status));
211                 return $status;
212         }
213
214         /**
215          * Reads a line, maximum 4096 Bytes from current file pointer
216          *
217          * @return      $data   Read data from file
218          */
219         public function readLine () {
220                 // Read whole line
221                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('FILE-INPUT-OUTPUT-POINTER: CALLED!');
222                 $data = $this->read();
223
224                 // Return data
225                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: data[%s]=%s - EXIT!', gettype($data), $data));
226                 return $data;
227         }
228
229         /**
230          * Reads given amount of bytes from file.
231          *
232          * @param       $bytes  Amount of bytes to read
233          * @return      $data   Data read from file
234          * @throws      OutOfBoundsException    If the position is not seekable
235          */
236         public function read (int $bytes = 0) {
237                 // Validatre parameter
238                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: bytes=%d - CALLED!', $bytes));
239                 if ($bytes < 0) {
240                         // Bytes cannot be lesser than zero
241                         throw new OutOfBoundsException(sprintf('bytes=%d is not valid', $bytes));
242                 }
243
244                 // Is $bytes bigger than zero?
245                 if ($bytes > 0) {
246                         // Try to read given characters
247                         $data = $this->getFileObject()->fread($bytes);
248                 } else {
249                         // Try to read whole line
250                         $data = $this->getFileObject()->fgets();
251                 }
252
253                 // Then return it
254                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: data[%s]=%s - EXIT!', gettype($data), $data));
255                 return $data;
256         }
257
258         /**
259          * Analyzes entries in index file. This will count all found (and valid)
260          * entries, mark invalid as damaged and count gaps ("fragmentation"). If
261          * only gaps are found, the file is considered as "virgin" (no entries).
262          *
263          * @return      void
264          * @throws      UnsupportedOperationException   If this method is called
265          */
266         public function analyzeFileStructure () {
267                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
268         }
269
270         /**
271          * Advances to next "block" of bytes
272          *
273          * @return      void
274          * @throws      UnsupportedOperationException   If this method is called
275          */
276         public function next () {
277                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
278         }
279
280         /**
281          * Checks wether the current entry is valid (not at the end of the file).
282          * This method will return true if an emptied (nulled) entry has been found.
283          *
284          * @return      $isValid        Whether the next entry is valid
285          * @throws      UnsupportedOperationException   If this method is called
286          */
287         public function valid () {
288                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
289         }
290
291         /**
292          * Gets current seek position ("key").
293          *
294          * @return      $key    Current key in iteration
295          * @throws      UnsupportedOperationException   If this method is called
296          */
297         public function key () {
298                 throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION);
299         }
300
301         /**
302          * "Getter" for file size
303          *
304          * @return      $fileSize       Size of currently loaded file
305          * @throws      UnexpectedValueException        If $fileData does not contain "size"
306          */
307         public function getFileSize () {
308                 // Get file's data
309                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('FILE-INPUT-OUTPUT-POINTER: CALLED!');
310                 $fileData = $this->getFileObject()->fstat();
311
312                 // Make sure the required array key is there
313                 if (!isset($fileData['size'])) {
314                         // Not valid array
315                         throw new UnexpectedValueException(sprintf('fileData=%s has no element "size"', print_r($fileData, TRUE)));
316                 }
317
318                 // Return size
319                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('FILE-INPUT-OUTPUT-POINTER: fileData[size]=%d - EXIT!', $fileData['size']));
320                 return $fileData['size'];
321         }
322
323 }