Mercurial > code
view C++/Pack.h @ 219:8fc177bbc4a6
Update some code
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 08 May 2014 22:55:48 +0200 |
parents | 523156bb3af5 |
children | c6513d9c696b |
line wrap: on
line source
/* * 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<unsigned 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<unsigned char *>(&value), TypeInfo<T>::size); value = convert(value, endian); readFile(in, endian, args...); } public: /** * Host system endian mode. */ 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_