Move file IO to standalone class

Adds object oriented way to work with zlib. Error handling for file IO
is based on C++ exceptions.
Replaces printf-like output with direct writing. This prevents buffer
overflow in zlib during write operations.

Change-Id: I626be309250c623cd60021ee6c17518855a171a6
Signed-off-by: Artem Senichev <a.senichev@yadro.com>
diff --git a/src/log_file.cpp b/src/log_file.cpp
new file mode 100644
index 0000000..0f7a20a
--- /dev/null
+++ b/src/log_file.cpp
@@ -0,0 +1,76 @@
+/**
+ * @brief Log file.
+ *
+ * This file is part of HostLogger project.
+ *
+ * Copyright (c) 2020 YADRO
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "log_file.hpp"
+
+#include "zlib_exception.hpp"
+
+LogFile::LogFile(const char* fileName)
+{
+    fd_ = gzopen(fileName, "w");
+    if (fd_ == Z_NULL)
+        throw ZlibException(ZlibException::Create, Z_ERRNO, fd_, fileName);
+    fileName_ = fileName;
+}
+
+LogFile::~LogFile()
+{
+    if (fd_ != Z_NULL)
+        gzclose_w(fd_);
+}
+
+void LogFile::close()
+{
+    if (fd_ != Z_NULL)
+    {
+        const int rc = gzclose_w(fd_);
+        if (rc != Z_OK)
+            throw ZlibException(ZlibException::Close, rc, fd_, fileName_);
+        fd_ = Z_NULL;
+        fileName_.clear();
+    }
+}
+
+void LogFile::write(time_t timeStamp, const std::string& message) const
+{
+    int rc;
+
+    // Convert time stamp and write it
+    tm tmLocal;
+    localtime_r(&timeStamp, &tmLocal);
+    rc = gzprintf(fd_, "[ %02i:%02i:%02i ]: ", tmLocal.tm_hour, tmLocal.tm_min,
+                  tmLocal.tm_sec);
+    if (rc <= 0)
+        throw ZlibException(ZlibException::Write, rc, fd_, fileName_);
+
+    // Write message
+    const size_t len = message.length();
+    if (len)
+    {
+        rc = gzwrite(fd_, message.data(), static_cast<unsigned int>(len));
+        if (rc <= 0)
+            throw ZlibException(ZlibException::Write, rc, fd_, fileName_);
+    }
+
+    // Write EOL
+    rc = gzputc(fd_, '\n');
+    if (rc <= 0)
+        throw ZlibException(ZlibException::Write, rc, fd_, fileName_);
+}