changeset 185:523156bb3af5

Add Pack class Task: #213
author David Demelier <markand@malikania.fr>
date Fri, 15 Nov 2013 21:37:57 +0100
parents 4c746050969a
children d4b8416e9ab1
files C++/Pack.cpp C++/Pack.h
diffstat 2 files changed, 250 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Pack.cpp	Fri Nov 15 21:37:57 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Pack.cpp -- binary data serialization
+ *
+ * Copyright (c) 2013 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "Pack.h"
+
+namespace {
+
+Pack::Endian checkMode()
+{
+	int i = 1;
+	unsigned char *ptr = reinterpret_cast<unsigned char *>(&i);
+
+	return (ptr[0] == 1) ? Pack::Little : Pack::Big;
+}
+
+}
+
+const Pack::Endian Pack::mode = checkMode();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Pack.h	Fri Nov 15 21:37:57 2013 +0100
@@ -0,0 +1,217 @@
+/*
+ * Pack.h -- binary data serialization
+ *
+ * Copyright (c) 2013 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PACK_H_
+#define _PACK_H_
+
+#include <cstdint>
+#include <fstream>
+#include <stdexcept>
+#include <string>
+
+/**
+ * @class Pack
+ * @brief Serialize binary data to files
+ *
+ * This class write and read binary data from files. It currently
+ * support:
+ *	uint8_t,
+ *	uint16_t,
+ *	uint32_t,
+ *	uint64_t
+ */
+class Pack {
+public:
+	/**
+	 * @enum Endian
+	 * @brief Endian mode
+	 */
+	enum Endian {
+		Little,		//! Little endian
+		Big		//! Big endian
+	};
+
+private:
+	static void writeFile(std::ofstream &out, Endian endian)
+	{
+		// dummy, stop recursion
+	}
+
+	template <typename T, typename... Args>
+	static void writeFile(std::ofstream &out, Endian endian, const T &value, Args&... args)
+	{
+		static_assert(TypeInfo<T>::supported, "unsupported type");
+
+		T ret = convert(value, endian);
+		out.write(reinterpret_cast<char *>(&ret), TypeInfo<T>::size);
+		writeFile(out, endian, args...);
+	}
+
+	static void readFile(std::ifstream &in, Endian endian)
+	{
+		// dummy, stop recursion
+	}
+
+	template <typename T, typename... Args>
+	static void readFile(std::ifstream &in, Endian endian, T &value, Args&&... args)
+	{
+		static_assert(TypeInfo<T>::supported, "unsupported type");
+
+		in.read(reinterpret_cast<char *>(&value), TypeInfo<T>::size);
+		value = convert(value, endian);
+		readFile(in, endian, args...);
+	}
+
+public:
+	static const Endian mode;
+
+	/**
+	 * @struct TypeInfo
+	 * @brief Type information
+	 *
+	 * Used for conversions.
+	 */
+	template <typename T>
+	struct TypeInfo {
+		static const bool supported = false;
+		static const size_t size = 0;
+	};
+
+	/**
+	 * Convert data.
+	 *
+	 * @param value the value to convert if needed
+	 * @param endian the endian mode
+	 * @return the converted value
+	 */
+	template <typename T>
+	static T convert(T value, Endian endian);
+
+	/**
+	 * Write binary data to the file
+	 *
+	 * @param path the path to the file
+	 * @param endian the endian mode
+	 * @param args the arguments
+	 * @throw std::runtime_exception on error
+	 */
+	template <typename... Args>
+	static void write(const std::string &path,
+			  Endian endian,
+			  Args&&... args)
+	{
+		std::ofstream out;
+
+		out.open(path, std::ios_base::binary);
+		if (!out.is_open())
+			throw std::runtime_error("Can't open file for writing");
+
+		writeFile(out, endian, std::forward<Args>(args)...);
+	}
+
+	/**
+	 * Read binary data from the file
+	 *
+	 * @param path the path to the file
+	 * @param endian the endian mode
+	 * @param args the arguments
+	 * @throw std::runtime_exception on error
+	 */
+	template <typename... Args>
+	static void read(const std::string &path,
+			 Endian endian,
+			 Args&&... args)
+	{
+		std::ifstream in;
+
+		in.open(path, std::ios_base::binary);
+		if (!in.is_open())
+			throw std::runtime_error("Can't open file for reading");
+
+		readFile(in, endian, std::forward<Args>(args)...);
+	}
+};
+
+template <>
+struct Pack::TypeInfo<uint8_t> {
+	static const bool supported = true;
+	static const size_t size = 1;
+};
+
+template <>
+struct Pack::TypeInfo<uint16_t> {
+	static const bool supported = true;
+	static const size_t size = 2;
+};
+
+template <>
+struct Pack::TypeInfo<uint32_t> {
+	static const bool supported = true;
+	static const size_t size = 4;
+};
+
+template <>
+struct Pack::TypeInfo<uint64_t> {
+	static const bool supported = true;
+	static const size_t size = 8;
+};
+
+template <>
+uint8_t Pack::convert(uint8_t v, Endian)
+{
+	return v;
+}
+
+template <>
+uint16_t Pack::convert(uint16_t v, Endian endian)
+{
+	if (mode != endian)
+		return (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
+
+	return v;
+}
+
+template <>
+uint32_t Pack::convert(uint32_t v, Endian endian)
+{
+	if (mode != endian)
+		return ((((v) >> 24) & 0x000000FFL)
+		    | (((v) >> 8)  & 0x0000FF00L)
+		    | (((v) << 8)  & 0x00FF0000L)
+		    | (((v) << 24) & 0xFF000000L));
+
+	return v;
+}
+
+template <>
+uint64_t Pack::convert(uint64_t v, Endian endian)
+{
+	if (mode != endian)
+		return ((((v) & 0xff00000000000000ull) >> 56)
+			| (((v) & 0x00ff000000000000ull) >> 40)
+			| (((v) & 0x0000ff0000000000ull) >> 24)
+			| (((v) & 0x000000ff00000000ull) >> 8 )
+			| (((v) & 0x00000000ff000000ull) << 8 )
+			| (((v) & 0x0000000000ff0000ull) << 24)
+			| (((v) & 0x000000000000ff00ull) << 40)
+			| (((v) & 0x00000000000000ffull) << 56));
+
+	return v;
+}
+
+#endif // !_PACK_H_