3 * An universal class for file input/output streams.
5 * @author Roland Haeder <webmaster@ship-simu.org>
7 * @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software
8 * @license GNU GPL 3.0 or any newer version
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 class FileIOStream extends BaseFrameworkSystem implements FileInputStreamer, FileOutputStreamer {
27 private function __construct () {
28 // Call parent constructor
29 parent::constructor(__CLASS__);
31 // Set part description
32 $this->setPartDescr("Universal Datei-Ein-/Ausgabesystem");
35 $this->createUniqueID();
38 $this->removeNumberFormaters();
39 $this->removeSystemArray();
43 * Create a file IO stream. This is a class for performing all actions
44 * on files like creating, deleting and loading them.
46 * @return $ioInstance An instance of FileIOStream
48 public final static function createFileIOStream () {
49 // Create new instance
50 $ioInstance = new FileIOStream();
52 // Return the instance
57 * Saves data to a given local file
59 * @param $fileName The file name for the to be saved file
60 * @param $dataArray The data we shall store to the file
62 * @see FileOutputStreamer
64 public final function saveFile ($fileName, $dataArray) {
66 $dirName = ""; $fileInstance = null;
67 for ($idx = 0; $idx < 5; $idx++) {
68 // Get a file output pointer
70 $fileInstance = FrameworkFileOutputPointer::createFrameworkFileOutputPointer($fileName, 'w');
71 } catch (FilePointerNotOpenedException $e) {
72 // Create missing directory
73 $dirName = dirname($fileName);
74 for ($idx2 = 0; $idx2 < (2 - $idx); $idx2++) {
75 $dirName = dirname($dirName);
82 // Write a header information for validation purposes
83 $fileInstance->writeToFile(sprintf("@head^%s:%s:%s:%s\n",
86 strlen($dataArray[1]),
90 // Encode the (maybe) binary stream with Base64
91 $b64Stream = base64_encode($dataArray[1]);
93 // write the data line by line
94 $line = str_repeat(" ", 50); $idx = 0;
95 while (strlen($line) == 50) {
96 // Get 50 chars or less
97 $line = substr($b64Stream, $idx, 50);
99 // Save it to the stream
100 $fileInstance->writeToFile(sprintf("@data^%s:%s\n",
105 // Advance to the next 50-chars block
110 $fileInstance->closeFile();
114 * Reads from a local file
116 * @param $fqfn The full-qualified file-name which we shall load
117 * @return $array An array with the element 'header' and 'data'
118 * @see FileInputStreamer
120 public final function loadFileContents ($fqfn) {
121 // Initialize some variables and arrays
126 $readData = ""; // This will contain our read data
128 // Get a file input handler
129 $fileInstance = FrameworkFileInputPointer::createFrameworkFileInputPointer($fqfn);
131 // Read all it's contents (we very and transparently decompress it below)
132 while ($readRawLine = $fileInstance->readFromFile()) {
133 // Add the read line to the buffer
134 $inputBuffer .= $readRawLine;
136 // Break infinite loop maybe caused by the input handler
137 if ($lastBuffer == $inputBuffer) break;
139 // Remember last read line for avoiding possible infinite loops
140 $lastBuffer = $inputBuffer;
143 // Close directory handle
144 $fileInstance->closeFile();
146 // Convert it into an array
147 $inputBuffer = explode("\n", $inputBuffer);
149 // Now process the read lines and verify it's content
150 foreach ($inputBuffer as $rawLine) {
151 // Trim it a little but not the leading spaces/tab-stops
152 $rawLine = rtrim($rawLine);
155 if (substr($rawLine, 0, 5) == "@head") {
156 // Header found, so let's extract it
157 $header = explode("^", $rawLine);
158 $header = trim($header[1]);
160 // Now we must convert it again into an array
161 $header = explode(":", $header);
163 // Is the header (maybe) valid?
164 if (count($header) != 4) {
165 // Throw an exception
166 throw new InvalidArrayCountException(array($this, "header", count($header), 4), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT);
168 } elseif (substr($rawLine, 0, 5) == "@data") {
170 $data = explode("^", $rawLine);
173 // First element is the data, second the MD5 checksum
174 $data = explode(":", $data);
176 // Validate the read line
177 if (count($data) == 2) {
178 if (md5($data[0]) != $data[1]) {
179 // MD5 hash did not match!
180 throw new InvalidMD5ChecksumException(array($this, md5($data[0]), $data[1]), self::EXCEPTION_MD5_CHECKSUMS_MISMATCH);
184 throw new InvalidArrayCountException(array($this, "data", count($data), 2), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT);
187 // Add this to the readData string
188 $readData .= $data[0];
190 // Other raw lines than header/data tagged lines and re-add the new-line char
191 $readData .= $rawLine."\n";
195 // Was raw lines read and no header/data?
196 if ((!empty($readData)) && (count($header) == 0) && (count($data) == 0)) {
197 // Return raw lines back
201 // Was a header found?
202 if (count($header) != 4) {
203 // Throw an exception
204 throw new InvalidArrayCountException(array($this, "header", count($header), 4), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT);
207 // Decode all from Base64
208 $readData = @base64_decode($readData);
210 // Does the size match?
211 if (strlen($readData) != $header[2]) {
212 // Size did not match
213 throw new InvalidDataLengthException(array($this, strlen($readData), $header[2]), self::EXCEPTION_UNEXPECTED_STRING_SIZE);
216 // Validate the decoded data with the final MD5 hash
217 if (md5($readData) != $header[3]) {
218 // MD5 hash did not match!
219 throw new InvalidMD5ChecksumException(array($this, md5($readData), $header[3]), self::EXCEPTION_MD5_CHECKSUMS_MISMATCH);
222 // Return all in an array