]> git.mxchange.org Git - core.git/blob - framework/main/classes/file_directories/binary/class_BaseBinaryFile.php
4ed66c22dbc482b1c1deb5ae43c377e5993432e5
[core.git] / framework / main / classes / file_directories / binary / class_BaseBinaryFile.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Filesystem\File;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
8 use Org\Mxchange\CoreFramework\Filesystem\Block;
9 use Org\Mxchange\CoreFramework\Filesystem\Block\CalculatableBlock;
10 use Org\Mxchange\CoreFramework\Filesystem\File\BaseAbstractFile;
11
12 // Import SPL stuff
13 use \BadMethodCallException;
14 use \InvalidArgumentException;
15 use \SplFileInfo;
16 use \UnexpectedValueException;
17
18 /**
19  * A general binary file class
20  *
21  * @author              Roland Haeder <webmaster@ship-simu.org>
22  * @version             0.0.0
23  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
24  * @license             GNU GPL 3.0 or any newer version
25  * @link                http://www.ship-simu.org
26  *
27  * This program is free software: you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License as published by
29  * the Free Software Foundation, either version 3 of the License, or
30  * (at your option) any later version.
31  *
32  * This program is distributed in the hope that it will be useful,
33  * but WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35  * GNU General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License
38  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
39  */
40 abstract class BaseBinaryFile extends BaseAbstractFile {
41         /**
42          * Separator for header data
43          */
44         const SEPARATOR_HEADER_DATA = 0x01;
45
46         /**
47          * Separator header->entries
48          */
49         const SEPARATOR_HEADER_ENTRIES = 0x02;
50
51         /**
52          * Separator group->hash
53          */
54         const SEPARATOR_GROUP_HASH = 0x03;
55
56         /**
57          * Separator hash->value
58          */
59         const SEPARATOR_HASH_VALUE = 0x04;
60
61         /**
62          * Separator entry->entry
63          */
64         const SEPARATOR_ENTRIES = 0x05;
65
66         /**
67          * Separator type->position
68          */
69         const SEPARATOR_TYPE_POSITION = 0x06;
70
71         /**
72          * Length of count
73          */
74         const LENGTH_COUNT = 20;
75
76         /**
77          * Length of position
78          */
79         const LENGTH_POSITION = 20;
80
81         /**
82          * Length of group
83          */
84         const LENGTH_GROUP = 10;
85
86         /**
87          * Maximum length of entry type
88          */
89         const LENGTH_TYPE = 20;
90
91         //***** Array elements for 'gaps' array *****
92
93         /**
94          * Start of gap
95          */
96         const GAPS_INDEX_START = 'start';
97
98         /**
99          * End of gap
100          */
101         const GAPS_INDEX_END = 'end';
102
103         /**
104          * Current seek position
105          */
106         private $seekPosition = 0;
107
108         /**
109          * Size of header
110          */
111         private $headerSize = 0;
112
113         /**
114          * File header
115          */
116         private $header = [];
117
118         /**
119          * Seek positions for gaps ("fragmentation")
120          */
121         private $gaps = [];
122
123         /**
124          * Seek positions for damaged entries (e.g. mismatching hash sum, ...)
125          */
126         private $damagedEntries = [];
127
128         /**
129          * Back-buffer
130          */
131         private $backBuffer = '';
132
133         /**
134          * Currently loaded block (will be returned by current())
135          */
136         private $currentBlock = '';
137
138         /**
139          * An instance of a Block class
140          */
141         private $blockInstance = NULL;
142
143         /**
144          * Protected constructor
145          *
146          * @param       $className      Name of the class
147          * @return      void
148          */
149         protected function __construct (string $className) {
150                 // Call parent constructor
151                 parent::__construct($className);
152
153                 // Init counters and gaps array
154                 $this->initCountersGapsArray();
155         }
156
157         /**
158          * Setter for Block instance
159          *
160          * @param       $blockInstance  An instance of an Block class
161          * @return      void
162          */
163         protected final function setBlockInstance (Block $blockInstance) {
164                 $this->blockInstance = $blockInstance;
165         }
166
167         /**
168          * Getter for Block instance
169          *
170          * @return      $blockInstance  An instance of an Block class
171          */
172         public final function getBlockInstance () {
173                 return $this->blockInstance;
174         }
175
176         /**
177          * Setter for backBuffer field
178          *
179          * @param       $backBuffer             Characters to "store" in back-buffer
180          * @return      void
181          */
182         private function setBackBuffer (string $backBuffer) {
183                 // ... and set it
184                 $this->backBuffer = $backBuffer;
185         }
186
187         /**
188          * Getter for backBuffer field
189          *
190          * @return      $backBuffer             Characters "stored" in back-buffer
191          */
192         private function getBackBuffer () {
193                 return $this->backBuffer;
194         }
195
196         /**
197          * Setter for currentBlock field
198          *
199          * @param       $currentBlock   Characters to set a currently loaded block
200          * @return      void
201          */
202         private function setCurrentBlock (string $currentBlock) {
203                 // ... and set it
204                 $this->currentBlock = $currentBlock;
205         }
206
207         /**
208          * Gets currently read data
209          *
210          * @return      $current        Currently read data
211          */
212         public function getCurrentBlock () {
213                 // Return it
214                 return $this->currentBlock;
215         }
216
217         /**
218          * Getter for header size
219          *
220          * @return      $totalEntries   Size of file header
221          */
222         public final function getHeaderSize () {
223                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->headerSize=%d - CALLED!', $this->headerSize));
224                 return $this->headerSize;
225         }
226
227         /**
228          * Setter for header size
229          *
230          * @param       $headerSize             Size of file header
231          * @return      void
232          */
233         public final function setHeaderSize (int $headerSize) {
234                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting headerSize=%d - CALLED!', $headerSize));
235                 $this->headerSize = $headerSize;
236         }
237
238         /**
239          * Getter for header array
240          *
241          * @return      $totalEntries   Size of file header
242          */
243         public final function getHeader () {
244                 // Get it
245                 return $this->header;
246         }
247
248         /**
249          * Setter for header
250          *
251          * @param       $header         Array for a file header
252          * @return      void
253          */
254         public final function setHeader (array $header) {
255                 // Set it
256                 $this->header = $header;
257         }
258
259         /**
260          * Getter for seek position
261          *
262          * @return      $seekPosition   Current seek position (stored here in object)
263          */
264         public final function getSeekPosition () {
265                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Getting this->seekPosition=%d - CALLED!', $this->seekPosition));
266                 return $this->seekPosition;
267         }
268
269         /**
270          * Setter for seek position
271          *
272          * @param       $seekPosition   Current seek position (stored here in object)
273          * @return      void
274          */
275         protected final function setSeekPosition (int $seekPosition) {
276                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting seekPosition=%d - CALLED!', $seekPosition));
277                 $this->seekPosition = $seekPosition;
278         }
279
280         /**
281          * Marks whole file as gaps-only (freshly created file
282          *
283          * @param       $type   Type of file
284          * @param       $minimumBlockLength             Minimum block length
285          * @return      void
286          */
287         private function markFileGapsOnly (string $type, int $minimumBlockLength) {
288                 // Very simple to do ...
289                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: type=%s,minimumBlockLength=%d - CALLED!', $type, $minimumBlockLength));
290                 for ($idx = 0; $idx < FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_count'); $idx++) {
291                         // Mark start and end position as gap
292                         $this->addGap($idx * $minimumBlockLength, $idx * $minimumBlockLength + $minimumBlockLength);
293                 }
294
295                 // Trace message
296                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
297         }
298
299         /**
300          * Checks whether the abstracted file only contains gaps by counting all
301          * gaps' bytes together and compare it to total length.
302          *
303          * @return      $isGapsOnly             Whether the abstracted file only contains gaps
304          */
305         private function isFileGapsOnly () {
306                 // Count every gap
307                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
308                 $gapsSize = 0;
309                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: this->gaps()=%d', count($this->gaps)));
310                 foreach ($this->gaps as $gap) {
311                         // Calculate size of found gap: end-start including both
312                         /* 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]));
313                         $gapsSize += ($gap[self::GAPS_INDEX_END] - $gap[self::GAPS_INDEX_START]);
314
315                         // Debug message
316                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: gapsSize=%d', $gapsSize));
317                 }
318
319                 // Total gap size + header size must be same as file size
320                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: gapsSize=%d,this->fileSize=%d', $gapsSize, $this->getFileSize()));
321                 $isGapsOnly = ($gapsSize + 1 == $this->getFileSize());
322
323                 // Return status
324                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isGapsOnly=%d - EXIT!', intval($isGapsOnly)));
325                 return $isGapsOnly;
326         }
327
328         /**
329          * Adds a gap for given start and end position
330          *
331          * @param       $startPosition  Start seek position
332          * @param       $endPosition    End seek position
333          * @return      void
334          */
335         private function addGap(int $startPosition, int $endPosition) {
336                 // Push to gaps array
337                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: startPosition=%d,endPosition=%d - CALLED!', $startPosition, $endPosition));
338                 array_push($this->gaps, [
339                         self::GAPS_INDEX_START  => $startPosition,
340                         self::GAPS_INDEX_END    => $endPosition,
341                 ]);
342
343                 // Trace message
344                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
345         }
346
347         /**
348          * Initializes the back-buffer by setting it to an empty string.
349          *
350          * @return      void
351          */
352         private function initBackBuffer () {
353                 // Simply call the setter
354                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
355                 $this->setBackBuffer('');
356
357                 // Trace message
358                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
359         }
360
361         /**
362          * Seeks to beginning of file, updates seek position in this object and
363          * flushes the header.
364          *
365          * @param       $flushHeader    Wether the file's header should be flushed (default: false)
366          * @return      void
367          */
368         protected function rewindUpdateSeekPosition (bool $flushHeader = false) {
369                 // Seek to beginning of file
370                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: flushHeader=%d - CALLED!', intval($flushHeader)));
371                 $this->rewind();
372
373                 // And update seek position ...
374                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->updateSeekPosition() ...');
375                 $this->updateSeekPosition();
376
377                 // Flush headers?
378                 if ($flushHeader) {
379                         // ... to write it back into the file
380                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
381                         $this->flushFileHeader();
382                 }
383
384                 // Trace message
385                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
386         }
387
388         /**
389          * Seeks to old position
390          *
391          * @return      void
392          */
393         protected function seekToOldPosition () {
394                 // Seek to currently ("old") saved position
395                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
396                 $this->seek($this->getSeekPosition());
397
398                 // Trace message
399                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
400         }
401
402         /**
403          * Initializes this file class
404          *
405          * @param       $fileInfoInstance       An instance of a SplFileInfo class
406          * @return      void
407          */
408         protected function initFile (SplFileInfo $fileInfoInstance) {
409                 // Get a file i/o pointer instance
410                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: fileInfoInstance[%s]=%s - CALLED!', get_class($fileInfoInstance), $fileInfoInstance));
411                 $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($fileInfoInstance));
412
413                 // ... and set it here
414                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Setting pointerInstance=%s ...', $pointerInstance->__toString()));
415                 $this->setPointerInstance($pointerInstance);
416
417                 // Trace message
418                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
419         }
420
421         /**
422          * Marks the currently loaded block as empty (with length of the block)
423          *
424          * @param       $length         Length of the block
425          * @return      void
426          * @throws      InvalidArgumentException        If a parameter is invalid
427          */
428         protected function markCurrentBlockAsEmpty (int $length) {
429                 // Validate parameter
430                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d - CALLED!', $length));
431                 if ($length < 1) {
432                         // Length cannot below one
433                         throw new InvalidArgumentException(sprintf('length=%d is not valid', $length));
434                 }
435
436                 // Get current seek position
437                 $currentPosition = $this->key();
438
439                 // Now add it as gap entry
440                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: currentPosition=%d', $currentPosition));
441                 $this->addGap(($currentPosition - $length), $currentPosition);
442
443                 // Trace message
444                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
445         }
446
447         /**
448          * Initializes counter for valid entries, arrays for damaged entries and
449          * an array for gap seek positions. If you call this method on your own,
450          * please re-analyze the file structure. So you are better to call
451          * analyzeFileStructure() instead of this method.
452          *
453          * @return      void
454          */
455         public function initCountersGapsArray () {
456                 // Init counter and seek position to header size
457                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
458                 $this->setCounter(0);
459                 $this->setSeekPosition($this->getHeaderSize());
460
461                 // Init arrays
462                 $this->gaps = [];
463                 $this->damagedEntries = [];
464
465                 // Trace message
466                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
467         }
468
469         /**
470          * Updates seekPosition attribute from file to avoid to much access on file.
471          *
472          * @return      void
473          */
474         public function updateSeekPosition () {
475                 // Get key (= seek position)
476                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
477                 $seekPosition = $this->key();
478
479                 // And set it here
480                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d', $seekPosition));
481                 $this->setSeekPosition($seekPosition);
482
483                 // Trace message
484                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
485         }
486
487         /**
488          * Checks whether the block separator has been found
489          *
490          * @param       $str            String to look in
491          * @return      $isFound        Whether the block separator has been found
492          * @throws      InvalidArgumentException        If a parameter is not valid
493          */
494         public static function isBlockSeparatorFound (string $str) {
495                 // Validate parameter
496                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: str=%s - CALLED!', $str));
497                 if (empty($str)) {
498                         // Throw IAE
499                         throw new InvalidArgumentException('Parameter "str" is empty');
500                 }
501
502                 // Determine it
503                 $isFound = (strpos($str, chr(self::SEPARATOR_ENTRIES)) !== false);
504
505                 // Return result
506                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isFound=%d - EXIT!', intval($isFound)));
507                 return $isFound;
508         }
509
510         /**
511          * Writes data at given position
512          *
513          * @param       $seekPosition   Seek position
514          * @param       $data                   Data to be written
515          * @param       $flushHeader    Whether to flush the header (default: flush)
516          * @return      void
517          * @throws      InvalidArgumentException        If a parameter is invalid
518          */
519         public function writeData (int $seekPosition, string $data, bool $flushHeader = true) {
520                 // Validate parameter
521                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%s,data()=%d,flushHeader=%d - CALLED!', $seekPosition, strlen($data), intval($flushHeader)));
522                 if ($seekPosition < 0) {
523                         // Invalid seek position
524                         throw new InvalidArgumentException(sprintf('seekPosition=%d is not valid', $seekPosition));
525                 } elseif (empty($data)) {
526                         // Empty data is invalid, too
527                         throw new InvalidArgumentException('Parameter "data" is empty');
528                 }
529
530                 // Write data at given position
531                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->writeAtPosition(%d,%s) ...', $seekPosition, $data));
532                 $this->writeAtPosition($seekPosition, $data);
533
534                 // Increment counter
535                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->incrementCounter() ...');
536                 $this->incrementCounter();
537
538                 // Update seek position
539                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->updateSeekPosition() ...');
540                 $this->updateSeekPosition();
541
542                 // Flush the header?
543                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: flushHeader=%d', intval($flushHeader)));
544                 if ($flushHeader === true) {
545                         // Flush header
546                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
547                         $this->flushFileHeader();
548
549                         // Seek to old position
550                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->seekToOldPosition() ...');
551                         $this->seekToOldPosition();
552                 }
553
554                 // Trace message
555                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
556         }
557
558         /**
559          * Writes at given position by seeking to it.
560          *
561          * @param       $seekPosition   Seek position in file
562          * @param       $dataStream             Data to be written
563          * @return      mixed                   Number of writes bytes or false on error
564          * @throws      InvalidArgumentException        If a parameter is not valid
565          */
566         public function writeAtPosition (int $seekPosition, string $dataStream) {
567                 // Validate parameter
568                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d,dataStream(%d)=%s - CALLED!', $seekPosition, strlen($dataStream), $dataStream));
569                 if ($seekPosition < 0) {
570                         // Invalid seek position
571                         throw new InvalidArgumentException(sprintf('seekPosition=%d is not valid.', $seekPosition));
572                 } elseif (empty($dataStream)) {
573                         // Empty dataStream
574                         throw new InvalidArgumentException('Parameter "dataStream" is empty');
575                 }
576
577                 // Call pointer's method
578                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->pointerInstance->writeAtPosition(%d, %s) ...', $seekPosition, $dataStream));
579                 $status = $this->getPointerInstance()->writeAtPosition($seekPosition, $dataStream);
580
581                 // Return status
582                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: status[%s]=%d - EXIT!', gettype($status), $status));
583                 return $status;
584         }
585
586         /**
587          * Checks whether the file header is initialized
588          *
589          * @return      $isInitialized  Whether the file header is initialized
590          */
591         public function isFileHeaderInitialized () {
592                 // Default is not initialized
593                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
594                 $isInitialized = false;
595
596                 // Is the file initialized?
597                 if ($this->isFileInitialized()) {
598                         // Some bytes has been written, so rewind to start of it.
599                         $this->rewind();
600
601                         // Read file header
602                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->readFileHeader() ...');
603                         $this->readFileHeader();
604
605                         // Get header count
606                         $headerCount = count($this->getHeader());
607
608                         // The above method does already check the header
609                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: headerCount=%d', $headerCount));
610                         $isInitialized = ($headerCount > 0);
611                 }
612
613                 // Return result
614                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isInitialized=%d - EXIT!', intval($isInitialized)));
615                 return $isInitialized;
616         }
617
618         /**
619          * Checks whether the assigned file has been initialized
620          *
621          * @return      $isInitialized          Whether the file's size is zero
622          */
623         public function isFileInitialized () {
624                 // Get it from iterator which holds the pointer instance. If false is returned
625                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
626                 $fileSize = $this->size();
627
628                 /*
629                  * The returned file size should not be false or NULL as this means
630                  * that the pointer class does not work correctly.
631                  */
632                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: fileSize[%s]=%d', gettype($fileSize), $fileSize));
633                 assert(is_int($fileSize));
634
635                 // Is more than 0 returned?
636                 $isInitialized = ($fileSize > 0);
637
638                 // Return result
639                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isInitialized=%d - EXIT!', intval($isInitialized)));
640                 return $isInitialized;
641         }
642
643         /**
644          * Creates the assigned file
645          *
646          * @return      void
647          * @throws      BadMethodCallException  If this file's header is already initialized
648          */
649         public function createFileHeader () {
650                 // The file's header should not be initialized here
651                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
652                 if ($this->isFileHeaderInitialized()) {
653                         // Bad method call
654                         //* DEBUG-DIE: */ die(sprintf('[%s:%d]: this=%s', __METHOD__, __LINE__, print_r($this, TRUE)));
655                         throw new BadMethodCallException('File header is already initialized but method called');
656                 }
657
658                 // Simple flush file header which will create it.
659                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->flushFileHeader() ...');
660                 $this->flushFileHeader();
661
662                 // Rewind seek position (to beginning of file) and update/flush file header
663                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->rewindUpdateSeekPosition() ...');
664                 $this->rewindUpdateSeekPosition();
665
666                 // Trace message
667                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
668         }
669
670         /**
671          * Pre-allocates file (if enabled) with some space for later faster write access.
672          *
673          * @param       $type   Type of the file
674          * @return      void
675          * @throws      InvalidArgumentException        If a parameter is empty
676          */
677         public function preAllocateFile (string $type) {
678                 // Is it enabled?
679                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: type=%s - CALLED!', $type));
680                 if (empty($type)) {
681                         // Empty type
682                         throw new InvalidArgumentException('Parameter "type" is empty');
683                 } elseif (FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_enabled') != 'Y') {
684                         // Don't continue here.
685                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Not pre-allocating file.'));
686                         return;
687                 }
688
689                 // Message to user
690                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Pre-allocating file ...');
691
692                 // Calculate minimum length for one entry and get file size
693                 $minimumBlockLength = $this->getBlockInstance()->calculateMinimumBlockLength();
694                 $fileSize = $this->getFileSize();
695
696                 // Calulcate seek position
697                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: minimumBlockLength=%d,fileSize=%d', $minimumBlockLength, $fileSize));
698                 $seekPosition = $minimumBlockLength * FrameworkBootstrap::getConfigurationInstance()->getConfigEntry($type . '_pre_allocate_count') + $fileSize ;
699
700                 // Now simply write a NUL there. This will pre-allocate the file.
701                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->writeAtPosition(%d,NUL) ...', $seekPosition));
702                 $this->writeAtPosition($seekPosition, chr(0));
703
704                 // Is the seek position zero?
705                 if ($fileSize == 0) {
706                         // Mark file as gaps-only
707                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->markGapsOnly(%s) ...', $type));
708                         $this->markFileGapsOnly($type, $minimumBlockLength);
709                 } else {
710                         // Analyze file structure
711                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->analyzeFileStructure() ...');
712                         $this->analyzeFileStructure();
713                 }
714
715                 // Rewind seek position
716                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: Calling this->rewind() ...');
717                 $this->rewind();
718
719                 // Trace message
720                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
721         }
722
723         /**
724          * Determines seek position
725          *
726          * @return      $seekPosition   Current seek position
727          */
728         public function determineSeekPosition () {
729                 // Call pointer instance
730                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
731                 $seekPosition = $this->getPointerInstance()->determineSeekPosition();
732
733                 // Return position
734                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d - EXIT!', $seekPosition));
735                 return $seekPosition;
736         }
737
738         /**
739          * Seek to given offset (default) or other possibilities as fseek() gives.
740          *
741          * @param       $offset         Offset to seek to (or used as "base" for other seeks)
742          * @param       $whence         Added to offset (default: only use offset to seek to)
743          * @return      $status         Status of file seek: 0 = success, -1 = failed
744          * @throws      InvalidArgumentException         If a parameter is not valid
745          */
746         public function seek (int $offset, int $whence = SEEK_SET) {
747                 // Validate parameter
748                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: offset=%d,whence=%d - CALLED!', $offset, $whence));
749                 if ($offset < 0) {
750                         // No offset is smaller than zero
751                         throw new InvalidArgumentException(sprintf('offset=%d is not valid', $offset));
752                 }
753
754                 // Call pointer instance
755                 $status = $this->getPointerInstance()->seek($offset, $whence);
756
757                 // Return status
758                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: status[%s]=%d - EXIT!', gettype($status), $status));
759                 return $status;
760         }
761
762         /**
763          * Reads given amount of bytes from file.
764          *
765          * @param       $bytes  Amount of bytes to read
766          * @return      $data   Data read from file
767          * @throws      InvalidArgumentException         If a parameter is not valid
768          */
769         public function read (int $bytes = 0) {
770                 // Validate parameter
771                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: bytes=%d - CALLED!', $bytes));
772                 if ($bytes < 0) {
773                         // Throw IAE
774                         throw new InvalidArgumentException(sprintf('bytes=%d is not valid', $bytes));
775                 }
776
777                 // Call pointer instance
778                 $data = $this->getPointerInstance()->read($bytes);
779
780                 // Return data
781                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data[%s]=%s - EXIT!', gettype($data), $data));
782                 return $data;
783         }
784
785         /**
786          * Rewinds to the beginning of the file
787          *
788          * @return      void
789          */
790         public function rewind () {
791                 // Call pointer instance
792                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
793                 $this->getPointerInstance()->rewind();
794
795                 // Trace message
796                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
797         }
798
799         /**
800          * Analyzes entries in index file. This will count all found (and valid)
801          * entries, mark invalid as damaged and count gaps ("fragmentation"). If
802          * only gaps are found, the file is considered as "virgin" (no entries).
803          *
804          * @return      void
805          * @throws      BadMethodCallException  If this method is called but file is not initialized
806          */
807         public function analyzeFileStructure () {
808                 // Make sure the file is initialized
809                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
810                 if (!$this->isFileInitialized()) {
811                         // Bad method call
812                         throw new BadMethodCallException('Method called but file is not initialized.');
813                 }
814
815                 // Init counters and gaps array
816                 $this->initCountersGapsArray();
817
818                 // Output message (as this may take some time)
819                 self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('Analyzing file structure ... (this may take some time)'));
820
821                 // First rewind to the begining
822                 $this->rewind();
823
824                 // Then try to load all entries
825                 while ($this->valid()) {
826                         // Get current entry
827                         $current = $this->getCurrentBlock();
828
829                         /*
830                          * If the block is empty, maybe the whole file is? This could mean
831                          * that the file has been pre-allocated.
832                          */
833                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current[]=%s', gettype($current)));
834                         if (empty($current)) {
835                                 // Then skip this part
836                                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current[]=%s is empty - CONTINUE!', gettype($current)));
837                                 continue;
838                         }
839
840                         // Go to next entry
841                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current()=%d', strlen($current)));
842                         $this->next();
843                 }
844
845                 // If the last read block is empty, check gaps
846                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: current()=%d', strlen($current)));
847                 if (empty($current)) {
848                         // Output message
849                         self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('Found a total of %d gaps.', count($this->gaps)));
850
851                         // Check gaps, if the whole file is empty.
852                         if ($this->isFileGapsOnly()) {
853                                 // Only gaps, so don't continue here.
854                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: File is gaps-only - EXIT!');
855                                 return;
856                         }
857
858                         /*
859                          * The above call has calculated a total size of all gaps. If the
860                          * percentage of gaps passes a "soft" limit and last
861                          * defragmentation is to far in the past, or if a "hard" limit has
862                          * reached, run defragmentation.
863                          */
864                         if ($this->isDefragmentationNeeded()) {
865                                 // Run "defragmentation"
866                                 $this->doRunDefragmentation();
867                         }
868                 }
869
870                 // Trace message
871                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
872         }
873
874         /**
875          * Advances to next "block" of bytes
876          *
877          * @return      void
878          * @throws      UnexpectedValueException        If some unexpected value was found
879          */
880         public function next () {
881                 // Is there nothing to read?
882                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
883                 if (!$this->valid()) {
884                         // Nothing to read
885                         return;
886                 }
887
888                 // First calculate minimum block length
889                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: key()=%d', $this->key()));
890                 $length = $this->getBlockInstance()->calculateMinimumBlockLength();
891                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d', $length));
892
893                 // Read possibly back-buffered bytes from previous call of next().
894                 $data = $this->getBackBuffer();
895
896                 /*
897                  * Read until a entry/block separator has been found. The next read
898                  * "block" may not fit, so this loop will continue until the EOB or EOF
899                  * has been reached whatever comes first.
900                  */
901                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data()=%d', strlen($data)));
902                 while ((!$this->isEndOfFileReached()) && (empty($data) || !self::isBlockSeparatorFound($data))) {
903                         // Then read the next possible block
904                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling this->read(%d) ...', $length));
905                         $block = $this->read($length);
906
907                         // Is it all empty?
908                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: block()=%d,length=%s', strlen($block), $length));
909                         if (strlen(trim($block, chr(0))) == 0) {
910                                 // Mark this block as empty
911                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling markCurrentBlockAsEmpty(%d) ...', strlen($block)));
912                                 $this->markCurrentBlockAsEmpty(strlen($block));
913
914                                 // Skip to next block
915                                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CONTINUE!');
916                                 continue;
917                         }
918
919                         // At this block then
920                         $data .= $block;
921
922                         // A debug message
923                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data()=%d', strlen($data)));
924                 }
925
926                 // EOF reached?
927                 if ($this->isEndOfFileReached()) {
928                         // Set whole data as current read block
929                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: Calling setCurrentBlock(%d) ...', strlen($data)));
930                         $this->setCurrentBlock($data);
931
932                         // Then abort here silently
933                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EOF reached - EXIT!');
934                         return;
935                 }
936
937                 /*
938                  * Init back-buffer which is the data that has been found beyond the
939                  * separator.
940                  */
941                 $this->initBackBuffer();
942
943                 // Separate data
944                 $dataArray = explode(chr(self::SEPARATOR_ENTRIES), $data);
945
946                 // This array must contain two elements
947                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: dataArray()=%d', count($dataArray)));
948                 //* PRINTR-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: dataArray=%s', print_r($dataArray, true)));
949                 if (count($dataArray) != 2) {
950                         // Bad count
951                         throw new UnexpectedValueException(sprintf('dataArray()=%d is not expected, want 2', count($dataArray)));
952                 }
953
954                 // Left part is the actual block, right one the back-buffer data
955                 $this->setCurrentBlock($dataArray[0]);
956                 $this->setBackBuffer($dataArray[1]);
957
958                 // Trace message
959                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
960         }
961
962         /**
963          * Checks wether the current entry is valid (not at the end of the file).
964          * This method will return true if an emptied (nulled) entry has been found.
965          *
966          * @return      $isValid        Whether the next entry is valid
967          * @throws      UnexpectedValueException        If some value is not expected
968          */
969         public function valid () {
970                 // First calculate minimum block length
971                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
972                 $length = $this->getBlockInstance()->calculateMinimumBlockLength();
973
974                 // Short be more than zero!
975                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d', $length));
976                 if ($length < 1) {
977                         // Throw UVE
978                         throw new UnexpectedValueException(sprintf('length=%d is not expected', $length));
979                 }
980
981                 // Get current seek position
982                 $seekPosition = $this->key();
983
984                 // Then try to read it
985                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d', $seekPosition));
986                 $data = $this->read($length);
987
988                 // If some bytes could be read, all is fine
989                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: data[%s]()=%d', gettype($data), strlen($data)));
990                 $isValid = ((is_string($data)) && (strlen($data) > 0));
991
992                 // Get header size
993                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isValid=%d', intval($isValid)));
994                 $headerSize = $this->getHeaderSize();
995
996                 // Is the seek position at or beyond the header?
997                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d,headerSize=%d', $seekPosition, $headerSize));
998                 if ($seekPosition >= $headerSize) {
999                         // Seek back to old position
1000                         $isValid = ($isValid && $this->seek($seekPosition) === 0);
1001                 } else {
1002                         // Seek directly behind the header
1003                         $isValid = ($isValid && $this->seek($headerSize) === 0);
1004                 }
1005
1006                 // Return result
1007                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: isValid=%d - EXIT!', intval($isValid)));
1008                 return $isValid;
1009         }
1010
1011         /**
1012          * Gets current seek position ("key").
1013          *
1014          * @return      $key    Current key in iteration
1015          */
1016         public function key () {
1017                 // Call pointer instance
1018                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
1019                 $key = $this->getPointerInstance()->determineSeekPosition();
1020
1021                 // Return key
1022                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: key[%s]=%d - EXIT!', gettype($key), $key));
1023                 return $key;
1024         }
1025
1026         /**
1027          * Reads the file header
1028          *
1029          * @return      void
1030          */
1031         public function readFileHeader () {
1032                 // Call block instance
1033                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
1034                 $this->getBlockInstance()->readFileHeader();
1035
1036                 // Trace message
1037                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
1038         }
1039
1040         /**
1041          * Flushes the file header
1042          *
1043          * @return      void
1044          */
1045         public function flushFileHeader () {
1046                 // Call block instance
1047                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: CALLED!');
1048                 $this->getBlockInstance()->flushFileHeader();
1049
1050                 // Trace message
1051                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-BINARY-FILE: EXIT!');
1052         }
1053
1054         /**
1055          * Searches for next suitable gap the given length of data can fit in
1056          * including padding bytes.
1057          *
1058          * @param       $length                 Length of raw data
1059          * @return      $seekPosition   Found next gap's seek position
1060          * @throws      InvalidArgumentException        If the parameter is not valid
1061          */
1062         public function searchNextGap (int $length) {
1063                 // If the file is only gaps, no need to seek
1064                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: length=%d - CALLED!', $length));
1065                 if ($length <= 0) {
1066                         // Throw IAE
1067                         throw new InvalidArgumentException(sprintf('length=%d is not valid', $length));
1068                 } elseif ($this->isFileGapsOnly()) {
1069                         /*
1070                          * The first empty block is the 2nd one right after the header, so
1071                          * one byte gap to the header.
1072                          */
1073                         $seekPosition = ($this->getHeaderSize() + 2);
1074
1075                         // Return position
1076                         /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-BINARY-FILE: seekPosition=%d - EXIT!', $seekPosition));
1077                         return $seekPosition;
1078                 }
1079
1080                 // @TODO Unfinished
1081                 $this->partialStub('length=' . $length);
1082         }
1083
1084 }