/* * Copyright (c) 2001 by Cliff Green. All rights reserved. Individual files * may be covered by other copyrights (as noted in the file itself). * * Redistribution and use in source and binary forms are permitted * provided that this entire copyright notice is duplicated in all such * copies. * * This software is provided "as is" and without any expressed or implied * warranties, including, without limitation, the implied warranties of * merchantibility and fitness for any particular purpose. */ //---------------------------------------------------------------------- // Source file: binarybuf.h // Written by: Cliff Green, 2001 // Compiler: Metrowerks CodeWarrior Pro 6 // History: // Modified: 8/22/2001 // By: Cliff Green // Comments: Generalized with template parameter for implementation // policy. // Modified: 9/09/2001 // By: Cliff Green // Comments: Minro tweaks for safety and additional documentation. //---------------------------------------------------------------------- // This commentheader supports documentation tools such as Doc++ and // Doxygen: http://www.doxygen.org/ //---------------------------------------------------------------------- /// Utility for binary buffer handling, using a std lib string implementation. /** * This header declares the BinaryBuf class and related utilities. The * BinaryBuf class is a (private) derivation of the std lib string * class (or a template parameter specifying a different string class * implementation with the same interface), removing unsafe interfaces * (anything taking a nul-terminated C-style string), and leaving the * interface restricted to the most commonly needed methods useful for * binary buffer handling. This class relies on the capability of std * lib strings being able to store any kind of characters, including * 0 (nul) characters. * * A few extensions are added, mostly as non-member functions, for * functionality such as I/O streaming to/from hex. * * Additional methods / interfaces can be added as needed - currently the * minimal needed set is implemented. * * The underlying char type (e.g. unsigned char vs char) is obtained from * the string implementation template parameter (value_type), and used in * the appropriate places. * * The template parameter corresponds to a storage / implementation policy, * which must match the std::basic_string interface. The default policy * is the std::string typedef (which is the std::basic_string class * instantiated on char. std::basic_string instantiated on unsigned char * or other character types works just as well. If the compiler vendor * supplied string class implementation is not acceptable, an alternative * string class implementation can be used, such as Andrei Alexandrescu's * templatized string class. * * The BinaryBuf class uses private inheritance (inheriting the * storage string class implementation rather than the public interface). * This keeps the application usage safe (since the std::basic_string * class is not meant for public derivation - there is not a virtual dtor). * * The reference material for this class was taken from Josuttis book: * "The C++ Standard Library", 1999. The storage policy concept is * taken from Stroustrup "The C++ Programming Language 3rd Ed" and from * Andrei Alexandrescu "Modern C++ Design", 2001. * * The hex utilities have a slight bit of non-portability and low-level * coding, but are fairly generalized and useful. The utility tester * only instantiates on 'char' and 'unsigned char' - there are almost * surely assumptions in this code which prevent 'wchar_t' from working * (without some non-trivial re-design). * * Usage examples: * * The default std::string template parameter type can be invoked with empty * angle syntax: * * Util::BinaryBuf<> b1; // create empty binary buf object, default imp * * Unsigned char can also be used to instantiate the underlying std::basic_string: * * Util::BinaryBuf > b2; * * Some other class that follows std::basic_string interface can be used: * * Util::BinaryBuf b3; * * * BinaryBufs can be created with arrays of the appropriate character type: * * char t[20]; * // ... * Util::BinaryBuf<> b4 (t, 20); // construct string from array * * The BinaryBuf class provides many string convenience methods (a1 and a2 are * the same BinaryBuf type, i.e. instantiated with the same template parameters): * * a1 == a2 * a1 += aChar * a1 = a2 * a1(a2) * a1.size() * a1.length() * a1[idx] * a1.data() * a1.push_back(aChar) * a1.clear() * a1.resize(someSize) * std::cout << a1 << std::endl; // output is hex representation * std::cin >> a1; // input stream must be valid hex characters * * * Note that the toHex function returns a std::string (which is the * basic_string class instantiated on char and default char traits). This * is for typical usage, and for ease in overloading the input and output * stream operators. These can be generalized, with a little bit of work, * to accept or return std::basic_string objects instantiated on other underlying * character types. * * Most of the pre-conditions and post-conditions should be obvious from usage - * e.g. any of the methods taking a length must have a valid length (corresponding * to the array being passed in), and character arrays must be non-null and of * appropriate size. A zero length with a valid array address is acceptable and * works as expected (default constructs, or appends nothing, etc). * * The stream input does have a few non-obvious pre-conditions - the character * stream must be composed of hex characters 0-9, A-F (uppercase). This matches * the format of the output stream (and toHex function). If this pre-condition * is not met, undefined (and invalid) results will occur. * * Some of the lower level hex to/from conversion functions operate only on * unsigned chars (and require an even number of hex characters), with the higher * level templatized version performing casts from the templatized type (e.g. char) * as appropriate. */ #ifndef BINARYBUF_H #define BINARYBUF_H #include #include #include #include // for size_t namespace Util { template < class T = std::string > class BinaryBuf : private T { public: // Expose desirable type definitions using typename T::traits_type; using typename T::value_type; using typename T::size_type; // Small set of desired constructors BinaryBuf () : T() { } // BinaryBuf (const BinaryBuf& rhs) : T(rhs) { } // implicit copy ctor BinaryBuf (const value_type* buf, size_type len) : T(buf, len) { } BinaryBuf (size_type num, value_type c) : T(num, c) { } // ~BinaryBuf() { } // implicit dtor // Expose desirable size and capacity base class methods using T::length; using T::size; using T::empty; using T::max_size; using T::capacity; using T::reserve; // Expose or extend desirable comparison methods - some are non-member fcts // declared after this class int compare (const BinaryBuf& rhs) const { return T::compare(rhs); } // Expose desirable access base class methods value_type operator[](size_type i) const { return T::operator[](i); } value_type& operator[] (size_type i) { return T::operator[](i); } using T::at; using T::data; using T::copy; // Expose or extend desirable modifying methods // BinaryBuf& operator= (const BinaryBuf& rhs); // implicit assign op BinaryBuf& assign (const BinaryBuf& rhs) { T::assign(rhs); return *this; } BinaryBuf& assign (const value_type* buf, size_type len) { T::assign(buf, len); return *this; } void swap (BinaryBuf& rhs) { T::swap(rhs); } BinaryBuf& operator+= (const BinaryBuf& rhs) { return append(rhs); } BinaryBuf& append (const BinaryBuf& rhs) { T::append(rhs); return *this; } BinaryBuf& append (const value_type* buf, size_type len) { T::append(buf, len); return *this; } BinaryBuf& operator+= (value_type c) { T::operator+=(c); return *this; } void push_back (value_type c) { T::push_back(c); } using T::clear; using T::resize; // Searching, finding, substrings, replacing chars will be added as needed }; // non-member functions manipulating BinaryBufs template inline bool operator== (const BinaryBuf& lhs, const BinaryBuf& rhs) { return lhs.compare(rhs) == 0; } template inline bool operator!= (const BinaryBuf& lhs, const BinaryBuf& rhs) { return !(lhs == rhs); } template inline const BinaryBuf operator+ (const BinaryBuf& lhs, const BinaryBuf& rhs) { BinaryBuf t(lhs); return (t += rhs); } template inline void swap (BinaryBuf& lhs, BinaryBuf& rhs) { lhs.swap(rhs); } typedef BinaryBuf > BinBufUnChar; // hex conversions, operator overloading for character mode input and output const std::string toHex (const unsigned char* buf, size_t len); // the following has a cast for calling the hex conversion routine, using the // data buffer of the BinaryBuf - conceivably this could result in undefined // behavior, but should be safe on just about any modern platform template inline const std::string toHex (const BinaryBuf& buf) { return toHex (reinterpret_cast(buf.data()), buf.length()); } unsigned char fromHex (char c); const BinBufUnChar fromHex (const std::string&); template const T fromHex (const std::string&); template inline std::ostream& operator<< (std::ostream& os, const BinaryBuf& rhs) { return os << toHex(rhs); } template std::istream& operator>> (std::istream&, BinaryBuf&); // ---------- move to implementation file when 'export' is supported template const T fromHex (const std::string& s) { typedef typename T::value_type Char; BinBufUnChar tmp (fromHex (s.length() % 2 == 0 ? s : s + '0')); return T(reinterpret_cast(tmp.data()), tmp.length()); } template std::istream& operator>> (std::istream& is, BinaryBuf& rhs) { std::string s; is >> s; rhs.assign(fromHex(s)); return is; } // ---------- end of template function implementations } // end namespace #endif // end header