Mercurial > code
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_