From f65c68522992147ad24569c4996e5fdeafde71af Mon Sep 17 00:00:00 2001
From: Valentin <vintsukevich@gmail.com>
Date: Tue, 16 Feb 2016 00:23:42 +0300
Subject: [PATCH] INIT

---
 .gitIgnore                            |   1 +
 README.md                             |   2 +-
 composer.json                         |  23 +++
 phpunit.xml                           |  18 +++
 src/BinaryGenerator.php               | 200 ++++++++++++++++++++++++++
 src/Exceptions/GeneratorException.php |  15 ++
 src/Exceptions/HandlerException.php   |  15 ++
 src/Exceptions/ReadDataException.php  |  15 ++
 src/Exceptions/WriteDataException.php |  15 ++
 tests/BinaryTest.php                  |  32 +++++
 tests/assets/.empty                   |   0
 11 files changed, 335 insertions(+), 1 deletion(-)
 create mode 100644 .gitIgnore
 create mode 100644 composer.json
 create mode 100644 phpunit.xml
 create mode 100644 src/BinaryGenerator.php
 create mode 100644 src/Exceptions/GeneratorException.php
 create mode 100644 src/Exceptions/HandlerException.php
 create mode 100644 src/Exceptions/ReadDataException.php
 create mode 100644 src/Exceptions/WriteDataException.php
 create mode 100644 tests/BinaryTest.php
 create mode 100644 tests/assets/.empty

diff --git a/.gitIgnore b/.gitIgnore
new file mode 100644
index 0000000..723ef36
--- /dev/null
+++ b/.gitIgnore
@@ -0,0 +1 @@
+.idea
\ No newline at end of file
diff --git a/README.md b/README.md
index 3121a45..fd3d085 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,2 @@
 # binary
-Lightweight tool to read/write tons of data directly in file, skipping memory usage
+Lightweight tool to read/write tons of data directly in file, skipping memory usage
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..ececb30
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,23 @@
+{
+  "name": "vvval/binary",
+  "description": "Lightweight tool to read/write tons of data directly in file, skipping memory usage",
+  "authors": [
+    {
+      "name": "Valentin V / vvval",
+      "email": "vintsukevich@gmail.com"
+    }
+  ],
+  "require-dev": {
+    "phpunit/phpunit": "~4.0"
+  },
+  "autoload": {
+    "psr-4": {
+      "Vvval\\Binary\\": "src"
+    }
+  },
+  "autoload-dev": {
+    "psr-4": {
+      "Vvval\\Binary\\Tests\\": "tests"
+    }
+  }
+}
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..94dc2bd
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         verbose="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+         stopOnError="false"
+         syntaxCheck="true">
+    <testsuites>
+        <testsuite name="Application Tests">
+            <directory>./tests/</directory>
+        </testsuite>
+    </testsuites>
+</phpunit>
\ No newline at end of file
diff --git a/src/BinaryGenerator.php b/src/BinaryGenerator.php
new file mode 100644
index 0000000..7d21481
--- /dev/null
+++ b/src/BinaryGenerator.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * Lightweight tool to read/write tons of data directly in file, skipping memory usage
+ *
+ * @author  Valentin V
+ * @license http://www.opensource.org/licenses/MIT
+ * @link    https://github.com/vvval/binary
+ * @version 0.1.0
+ */
+namespace Vvval\Binary;
+
+use Vvval\Binary\Exceptions\HandlerException;
+use Vvval\Binary\Exceptions\ReadDataException;
+use Vvval\Binary\Exceptions\WriteDataException;
+
+class BinaryGenerator
+{
+    /**
+     * todo read about fopen
+     */
+    const READ = 'rb';
+    const WRITE = 'wb';
+    const APPEND = 'ab';
+
+    private $filename = null;
+    private $compression = null;
+    private $handler = null;
+    private $mode = self::READ;
+
+    /**
+     * @param $compression
+     * @return $this
+     * @throws HandlerException
+     */
+    public function setCompression($compression)
+    {
+        if (!empty($this->handler))
+        {
+            throw new HandlerException("Binary generator has already started with \"$this->filename\" file.");
+        }
+
+        $this->compression = $compression;
+
+        return $this;
+    }
+
+    /**
+     * @param $filename
+     * @param $mode
+     * @throws HandlerException
+     */
+    public function start($filename, $mode)
+    {
+        $this->mode = $mode;
+        $this->filename = $filename;
+
+        if (!empty($this->handler))
+        {
+            throw new HandlerException("Binary generator has already started with \"$this->filename\" file.");
+        }
+
+        if (!empty($this->compression))
+        {
+            $this->handler = gzopen($this->filename, $this->mode);
+        }
+        else
+        {
+            $this->handler = fopen($this->filename, $this->mode);
+        }
+
+        if (empty($this->handler))
+        {
+            throw new HandlerException("Error during opening \"$this->filename\" file.");
+        }
+    }
+
+    /**
+     *
+     */
+    public function finish()
+    {
+        if (!empty($this->handler))
+        {
+            if (!empty($this->compression))
+            {
+                gzclose($this->handler);
+            }
+            else
+            {
+                fclose($this->handler);
+            }
+
+            $this->handler = null;
+        }
+    }
+
+    /**
+     * @param $data
+     * @return int
+     * @throws HandlerException
+     * @throws WriteDataException
+     */
+    public function writeData($data)
+    {
+        if (!$this->isWriteMode())
+        {
+            throw new WriteDataException("Unable to write data into \"$this->filename\" file, read mode is set.");
+        }
+
+        if (empty($this->handler))
+        {
+            throw new HandlerException("Unable to write data into \"$this->filename\" file, no resource is available.");
+        }
+
+        $packedLength = pack('L', mb_strlen($data));
+
+        if (!empty($this->compression))
+        {
+            return gzwrite($this->handler, $packedLength . $data);
+        }
+
+        return fwrite($this->handler, $packedLength . $data);
+    }
+
+    /**
+     * @return null|string
+     * @throws HandlerException
+     * @throws ReadDataException
+     */
+    public function readData()
+    {
+        if (!$this->isReadMode())
+        {
+            throw new ReadDataException("Unable to read data from \"$this->filename\" file, write mode is set.");
+        }
+
+        if (empty($this->handler))
+        {
+            throw new HandlerException("Unable to read data from \"$this->filename\" file, no resource is available.");
+        }
+
+        if (!empty($this->compression))
+        {
+            $length = gzread($this->handler, 4);
+        }
+        else
+        {
+            $length = fread($this->handler, 4);
+        }
+
+        if (empty($length))
+        {
+            return null;
+        }
+
+        if (mb_strlen($length) != 4)
+        {
+            throw new ReadDataException("Unable to read data from \"$this->filename\" file, data is corrupted.");
+        }
+
+        $length = unpack('L', $length);
+
+        if (!empty($this->compression))
+        {
+            return gzread($this->handler, $length[1]);
+        }
+        else
+        {
+            return fread($this->handler, $length[1]);
+        }
+    }
+
+    /**
+     * @return bool
+     */
+    private function isReadMode()
+    {
+        return $this->mode === self::READ;
+    }
+
+    /**
+     * @return bool
+     */
+    private function isWriteMode()
+    {
+        return in_array($this->mode, [self::WRITE, self::APPEND]);
+    }
+
+    /**
+     * Check if file was closed.
+     *
+     */
+    public function __destruct()
+    {
+        if (!empty($this->handler))
+        {
+            throw new HandlerException("Binary generator hasn't finished \"$this->filename\" file yet.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Exceptions/GeneratorException.php b/src/Exceptions/GeneratorException.php
new file mode 100644
index 0000000..eda7391
--- /dev/null
+++ b/src/Exceptions/GeneratorException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Lightweight tool to read/write tons of data directly in file, skipping memory usage
+ *
+ * @author  Valentin V
+ * @license http://www.opensource.org/licenses/MIT
+ * @link    https://github.com/vvval/binary
+ * @version 0.1.0
+ */
+namespace Vvval\Binary\Exceptions;
+
+class GeneratorException extends \Exception
+{
+
+}
\ No newline at end of file
diff --git a/src/Exceptions/HandlerException.php b/src/Exceptions/HandlerException.php
new file mode 100644
index 0000000..bc78116
--- /dev/null
+++ b/src/Exceptions/HandlerException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Lightweight tool to read/write tons of data directly in file, skipping memory usage
+ *
+ * @author  Valentin V
+ * @license http://www.opensource.org/licenses/MIT
+ * @link    https://github.com/vvval/binary
+ * @version 0.1.0
+ */
+namespace Vvval\Binary\Exceptions;
+
+class HandlerException extends GeneratorException
+{
+
+}
\ No newline at end of file
diff --git a/src/Exceptions/ReadDataException.php b/src/Exceptions/ReadDataException.php
new file mode 100644
index 0000000..a29077d
--- /dev/null
+++ b/src/Exceptions/ReadDataException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Lightweight tool to read/write tons of data directly in file, skipping memory usage
+ *
+ * @author  Valentin V
+ * @license http://www.opensource.org/licenses/MIT
+ * @link    https://github.com/vvval/binary
+ * @version 0.1.0
+ */
+namespace Vvval\Binary\Exceptions;
+
+class ReadDataException extends GeneratorException
+{
+
+}
\ No newline at end of file
diff --git a/src/Exceptions/WriteDataException.php b/src/Exceptions/WriteDataException.php
new file mode 100644
index 0000000..070eec6
--- /dev/null
+++ b/src/Exceptions/WriteDataException.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Lightweight tool to read/write tons of data directly in file, skipping memory usage
+ *
+ * @author  Valentin V
+ * @license http://www.opensource.org/licenses/MIT
+ * @link    https://github.com/vvval/binary
+ * @version 0.1.0
+ */
+namespace Vvval\Binary\Exceptions;
+
+class WriteDataException extends GeneratorException
+{
+
+}
\ No newline at end of file
diff --git a/tests/BinaryTest.php b/tests/BinaryTest.php
new file mode 100644
index 0000000..6f01f70
--- /dev/null
+++ b/tests/BinaryTest.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Valentin
+ * Date: 01.02.2016
+ * Time: 13:19
+ */
+
+namespace Vvval\Binary\Tests;
+
+use Vvval\Binary\BinaryGenerator;
+
+class BinaryTest extends \PHPUnit_Framework_TestCase
+{
+    private $writeFile = 'binary.write.txt';
+    private $appendFile = 'binary.append.txt';
+
+    /**
+     * If data file exists.
+     */
+    public function testBinaryWrite()
+    {
+        $binary = new BinaryGenerator();
+
+        $binary->start($this->writeFile, BinaryGenerator::WRITE);
+        $binary->writeData('some data.1');
+        $binary->writeData('some data.2');
+        $binary->finish();
+
+        $this->assertFileExists($this->writeFile);
+    }
+}
\ No newline at end of file
diff --git a/tests/assets/.empty b/tests/assets/.empty
new file mode 100644
index 0000000..e69de29