Moved analyzeFile() to BaseFile where a much better place is (and duplicate
[core.git] / inc / classes / main / iterator / io / class_FileIoIterator.php
1 <?php
2 /**
3  * A file i/o iterator
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 class FileIoIterator extends BaseIterator implements SeekableWritableFileIterator {
25         /**
26          * Back-buffer
27          */
28         private $backBuffer = '';
29
30         /**
31          * Currently loaded block (will be returned by current())
32          */
33         private $currentBlock = '';
34
35         /**
36          * Protected constructor
37          *
38          * @return      void
39          */
40         protected function __construct () {
41                 // Call parent constructor
42                 parent::__construct(__CLASS__);
43         }
44
45         /**
46          * Creates an instance of this class
47          *
48          * @param       $pointerInstance        An instance of a InputOutputPointer class
49          * @param       $blockInstance          An instance of a CalculatableBlock class
50          * @return      $iteratorInstance       An instance of a Iterator class
51          */
52         public final static function createFileIoIterator (InputOutputPointer $pointerInstance, CalculatableBlock $blockInstance) {
53                 // Get new instance
54                 $iteratorInstance = new FileIoIterator();
55
56                 // Set the instance here
57                 $iteratorInstance->setPointerInstance($pointerInstance);
58
59                 // Set the block instance here
60                 $iteratorInstance->setBlockInstance($blockInstance);
61
62                 // Return the prepared instance
63                 return $iteratorInstance;
64         }
65
66         /**
67          * Initializes the back-buffer by setting it to an empty string.
68          *
69          * @return      void
70          */
71         private function initBackBuffer () {
72                 // Simply call the setter
73                 $this->setBackBuffer('');
74         }
75
76         /**
77          * Setter for backBuffer field
78          *
79          * @param       $backBuffer             Characters to "store" in back-buffer
80          * @return      void
81          */
82         private function setBackBuffer ($backBuffer) {
83                 // Cast to string (so no arrays or objects)
84                 $backBuffer = (string) $backBuffer;
85
86                 // ... and set it
87                 $this->backBuffer = $backBuffer;
88         }
89
90         /**
91          * Getter for backBuffer field
92          *
93          * @return      $backBuffer             Characters "stored" in back-buffer
94          */
95         private function getBackBuffer () {
96                 return $this->backBuffer;
97         }
98
99         /**
100          * Setter for currentBlock field
101          *
102          * @param       $currentBlock           Characters to set a currently loaded block
103          * @return      void
104          */
105         private function setCurrentBlock ($currentBlock) {
106                 // Cast to string (so no arrays or objects)
107                 $currentBlock = (string) $currentBlock;
108
109                 // ... and set it
110                 $this->currentBlock = $currentBlock;
111         }
112
113         /**
114          * Gets currently read data
115          *
116          * @return      $current        Currently read data
117          */
118         public function current () {
119                 // Return it
120                 return $this->currentBlock;
121         }
122
123         /**
124          * Gets current seek position ("key").
125          *
126          * @return      $key    Current key in iteration
127          */
128         public function key () {
129                 // Return it
130                 return $this->getPointerInstance()->determineSeekPosition();
131         }
132
133         /**
134          * Advances to next "block" of bytes
135          *
136          * @return      void
137          * @todo        This method will load large but empty files in a whole
138          */
139         public function next () {
140                 // Is there nothing to read?
141                 if (!$this->valid()) {
142                         // Nothing to read
143                         return;
144                 } // END - if
145
146                 // First calculate minimum block length
147                 $length = $this->getBlockInstance()->caluclateMinimumBlockLength();
148
149                 // Short be more than zero!
150                 assert($length > 0);
151
152                 // Wait until a entry/block separator has been found
153                 $data = $this->getBackBuffer();
154                 while ((!$this->getPointerInstance()->isEndOfFileReached()) && (!$this->getBlockInstance()->isBlockSeparatorFound($data))) {
155                         // Then read the block
156                         $data .= $this->read($length);
157                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('data()=' . strlen($data));
158                 } // END - if
159
160                 // EOF reached?
161                 if ($this->getPointerInstance()->isEndOfFileReached()) {
162                         // Set whole data as current block
163                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('Calling setCurrentBlock(' . strlen($data) . ') ...');
164                         $this->setCurrentBlock($data);
165
166                         // Then abort here silently
167                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('EOF reached.');
168                         return;
169                 } // END - if
170
171                 /*
172                  * Init back-buffer which is the data that has been found beyond the
173                  * separator.
174                  */
175                 $this->initBackBuffer();
176
177                 // Separate data
178                 $dataArray = explode(self::getBlockSeparator(), $data);
179
180                 // This array must contain two elements
181                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('dataArray=' . print_r($dataArray, TRUE));
182                 assert(count($dataArray) == 2);
183
184                 // Left part is the actual block, right one the back-buffer data
185                 $this->setCurrentBlock($dataArray[0]);
186                 $this->setBackBuffer($dataArray[1]);
187         }
188
189         /**
190          * Rewinds to the beginning of the file
191          *
192          * @return      $status         Status of this operation
193          */
194         public function rewind () {
195                 // Call pointer instance
196                 return $this->getPointerInstance()->rewind();
197         }
198
199         /**
200          * Checks wether the current entry is valid (not at the end of the file).
201          * This method will return TRUE if an emptied (nulled) entry has been found.
202          *
203          * @return      $isValid        Whether the next entry is valid
204          */
205         public function valid () {
206                 // First calculate minimum block length
207                 $length = $this->getBlockInstance()->caluclateMinimumBlockLength();
208
209                 // Short be more than zero!
210                 assert($length > 0);
211
212                 // Get current seek position
213                 $seekPosition = $this->key();
214
215                 // Then try to read it
216                 $data = $this->read($length);
217
218                 // If some bytes could be read, all is fine
219                 $isValid = ((is_string($data)) && (strlen($data) > 0));
220
221                 // Get header size
222                 $headerSize = $this->getBlockInstance()->getHeaderSize();
223
224                 // Is the seek position at or beyond the header?
225                 if ($seekPosition >= $headerSize) {
226                         // Seek back to old position
227                         $this->seek($seekPosition);
228                 } else {
229                         // Seek directly behind the header
230                         $this->seek($headerSize);
231                 }
232
233                 // Return result
234                 return $isValid;
235         }
236
237         /**
238          * Seeks to given position
239          *
240          * @param       $seekPosition   Seek position in file
241          * @return      $status                 Status of this operation
242          */
243         public function seek ($seekPosition) {
244                 // Call pointer instance
245                 return $this->getPointerInstance()->seek($seekPosition);
246         }
247
248         /**
249          * Writes at given position by seeking to it.
250          *
251          * @param       $seekPosition   Seek position in file
252          * @param       $data                   Data to be written
253          * @return      void
254          */
255         public function writeAtPosition ($seekPosition, $data) {
256                 // First seek to it
257                 $this->seek($seekPosition);
258
259                 // Then write the data at that position
260                 $this->getPointerInstance()->writeToFile($data);
261         }
262
263         /**
264          * Size of file stack
265          *
266          * @return      $size   Size (in bytes) of file
267          */
268         public function size () {
269                 // Call the pointer object
270                 $size = $this->getPointerInstance()->size();
271
272                 // Return result
273                 return $size;
274         }
275
276         /**
277          * Reads given amount of bytes from file.
278          *
279          * @param       $bytes  Amount of bytes to read
280          * @return      $data   Data read from file
281          */
282         public function read ($bytes) {
283                 // Call pointer instance
284                 return $this->getPointerInstance()->read($bytes);
285         }
286
287         /**
288          * Analyzes entries in index file. This will count all found (and valid)
289          * entries, mark invalid as damaged and count gaps ("fragmentation"). If
290          * only gaps are found, the file is considered as "virgin" (no entries).
291          *
292          * @return      void
293          */
294         public function analyzeFile () {
295                 // Just call the pointer instance
296                 $this->getPointerInstance()->analyzeFile();
297         }
298 }
299
300 // [EOF]
301 ?>