VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ghexdump.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 ///
18 /// \file ghexdump.h
19 ///
20 /// Synopsis:
21 /// \code
22 /// G::hex_dump<16>( std::cout , data.begin() , data.end() ) ; // hex_dump
23 /// std::cout << G::hexdump<16>( data.begin() , data.end() ) ; // hexdump
24 /// \endcode
25 ///
26 
27 #ifndef G_HEXDUMP__H
28 #define G_HEXDUMP__H
29 
30 #include "gdef.h"
31 #include <iostream>
32 #include <cstddef>
33 #include <iomanip>
34 
35 namespace G
36 {
37  /// \namespace G::HexdumpImp
38  /// A private scope used for the implementation details of G::hexdump and G::hex_dump.
39  ///
40  namespace HexdumpImp
41  {
42  struct hexdump_tohex /// Nibble-to-hex-digit functor.
43  {
44  char operator()( unsigned int n ) { return "0123456789abcdef"[n] ; }
45  } ;
46 
47  struct hexdump_toprintable /// Char-to-printable-ascii functor.
48  {
49  char operator()( char c )
50  {
51  // allow only seven-bit ascii to avoid upsetting utf-8 xterms etc.
52  const unsigned int n = static_cast<unsigned char>(c) ;
53  return n >= 32U && n < 127U ? c : '.' ;
54  }
55  } ;
56 
57  template <unsigned N, typename Tin, typename Temit, typename Ttohex, typename Ttoprintable>
58  void hexdump_imp( Tin begin , Tin end , Temit & emitter , unsigned int width , Ttohex tohex , Ttoprintable toprintable )
59  {
60  width = width < N ? width : N ;
61 
62  char hexbuffer[N*3+2] ; // also holds last-line padding after the hex nul terminator
63  hexbuffer[N*3+1] = '\0' ;
64  char * const hexbuffer_end = hexbuffer+width*3 ;
65  *hexbuffer_end = '\0' ;
66  char * hex = hexbuffer ;
67 
68  char printablebuffer[N+1] ;
69  char * const printablebuffer_end = printablebuffer + width ;
70  *printablebuffer_end = '\0' ;
71  char * printable = printablebuffer ;
72 
73  std::size_t line_number = 0U ;
74  std::size_t address = 0U ;
75  for( Tin p = begin ; p != end ; ++p )
76  {
77  const unsigned int c = static_cast<unsigned char>(*p) ;
78  *hex++ = ' ' ;
79  *hex++ = tohex((c>>4)&0xf) ;
80  *hex++ = tohex(c&0xf) ;
81  *printable++ = toprintable(*p) ;
82  if( printable == printablebuffer_end )
83  {
84  emitter.emit( address , line_number , width , hexbuffer+1 , hexbuffer_end , printablebuffer ) ;
85  line_number++ ;
86  hex = hexbuffer ;
87  printable = printablebuffer ;
88  address += width ;
89  }
90  }
91  if( printable != printablebuffer )
92  {
93  *hex++ = '\0' ;
94  for( char * p = hex ; p != hexbuffer_end ; ++p ) *p = ' ' ;
95  *hexbuffer_end = ' ' ;
96  *printable = '\0' ;
97  emitter.emit( address , line_number , printable-printablebuffer , hexbuffer+1 , hex , printablebuffer ) ;
98  }
99  }
100 
101  struct hexdump_ostream_emitter /// An output adaptor to write to std::ostream.
102  {
103  explicit hexdump_ostream_emitter( std::ostream & out , unsigned int address_width , const char * prefix , const char * space , const char * bar ) :
104  m_out(out) ,
105  m_address_width(address_width) ,
106  m_prefix(prefix) ,
107  m_space(space) ,
108  m_bar(bar)
109  {
110  }
111  void emit( std::size_t address , std::size_t line_number , std::size_t /*line_length*/ , const char * hex , const char * padding , const char * printable )
112  {
113  m_out
114  << (line_number?"\n":"")
115  << m_prefix
116  << std::setfill('0') << std::setw(static_cast<int>(m_address_width)) << std::hex << address << std::dec
117  << m_space << hex
118  // (padding is always empty except for the last line; if there is padding on the first line
119  // then dont use it because a single line with lots of padding can look silly)
120  << (line_number?padding:"")
121  << m_bar << printable ;
122  }
123  std::ostream & m_out ;
124  unsigned int m_address_width ;
125  const char * m_prefix ;
126  const char * m_space ;
127  const char * m_bar ;
128  } ;
129 
130  template <unsigned N,typename T,typename Ttohex,typename Ttoprintable>
131  struct hexdump_streamable /// A streamable class used by G::hexdump().
132  {
133  hexdump_streamable( T begin , T end , int w ,
134  const char * prefix , const char * space , const char * bar ,
135  unsigned int width ,
136  Ttohex tohex , Ttoprintable toprintable ) :
137  m_begin(begin) ,
138  m_end(end) ,
139  m_w(w) ,
140  m_prefix(prefix) ,
141  m_space(space) ,
142  m_bar(bar) ,
143  m_width(width) ,
144  m_tohex(tohex) ,
145  m_toprintable(toprintable)
146  {
147  }
148  T m_begin ;
149  T m_end ;
150  int m_w ;
151  const char * m_prefix ;
152  const char * m_space ;
153  const char * m_bar ;
154  unsigned int m_width ;
155  Ttohex m_tohex ;
156  Ttoprintable m_toprintable ;
157  } ;
158 
159  template <unsigned N,typename T,typename Ttohex,typename Ttoprintable>
160  std::ostream & operator<<( std::ostream & stream , const hexdump_streamable<N,T,Ttohex,Ttoprintable> & hd )
161  {
162  hexdump_ostream_emitter emitter( stream , hd.m_w , hd.m_prefix , hd.m_space , hd.m_bar ) ;
163  hexdump_imp<N>( hd.m_begin , hd.m_end , emitter , hd.m_width , hd.m_tohex , hd.m_toprintable ) ;
164  return stream ;
165  }
166  }
167 
168  namespace imp = HexdumpImp ;
169 
170  /// Performs a hex dump to the given stream.
171  /// Eg.
172  /// \code
173  /// G::hex_dump<16>( std::cout , data.begin() , data.end() ) ;
174  /// \endcode
175  ///
176  template <int N,typename T,typename Ttohex,typename Ttoprintable>
177  void
178  hex_dump( std::ostream & out , T begin , T end ,
179  unsigned int address_width ,
180  const char * prefix , const char * space , const char * bar ,
181  unsigned int width ,
182  Ttohex tohex , Ttoprintable toprintable )
183  {
184  imp::hexdump_ostream_emitter emitter( out , address_width , prefix , space , bar ) ;
185  imp::hexdump_imp<N>( begin , end , emitter , width , tohex , toprintable ) ;
186  out << '\n' ;
187  }
188 
189  ///< defaulting overloads...
190 
191  template <int N,typename T> void
192  hex_dump( std::ostream & out , T begin , T end ,
193  unsigned int address_width ,
194  const char * prefix , const char * space , const char * bar ,
195  unsigned int width )
196  {
197  hex_dump<N,T,typename imp::hexdump_tohex,typename imp::hexdump_toprintable>( out , begin , end ,
198  address_width , prefix , space , bar , width ,
199  imp::hexdump_tohex() , imp::hexdump_toprintable() ) ;
200  }
201 
202  template <int N,typename T> void
203  hex_dump( std::ostream & out , T begin , T end ,
204  unsigned int address_width ,
205  const char * prefix , const char * space , const char * bar )
206  {
207  hex_dump<N,T>( out , begin , end ,
208  address_width , prefix , space , bar ,
209  N ) ;
210  }
211 
212  template <int N,typename T> void
213  hex_dump( std::ostream & out , T begin , T end ,
214  unsigned int address_width )
215  {
216  hex_dump<N,T>( out , begin , end , address_width , "" , " " , " | " ) ;
217  }
218 
219  template <int N,typename T> void
220  hex_dump( std::ostream & out , T begin , T end )
221  {
222  hex_dump<N,T>( out , begin , end , 6 ) ;
223  }
224 
225  ///< convenience overloads...
226 
227  template <int N,typename T> void
228  hex_dump( std::ostream & out , const T & str )
229  {
230  hex_dump<N,typename T::const_iterator>( out , str.begin() , str.end() ) ;
231  }
232 
233  /// Returns a streamable object that does a hex dump.
234  /// Eg.
235  /// \code
236  /// std::cout << G::hexdump<16>(data.begin(),data.end()) << std::endl ;
237  /// \endcode
238  ///
239  template <int N,typename T,typename Ttohex,typename Ttoprintable> imp::hexdump_streamable<N,T,Ttohex,Ttoprintable>
240  hexdump( T begin , T end ,
241  unsigned int address_width ,
242  const char * prefix , const char * space , const char * bar ,
243  unsigned int width ,
244  Ttohex tohex , Ttoprintable toprintable )
245  {
246  return imp::hexdump_streamable<N,T,Ttohex,Ttoprintable>( begin , end , address_width , prefix , space , bar , width , tohex , toprintable ) ;
247  }
248 
249  ///< defaulting overloads...
250 
251  template <int N,typename T> imp::hexdump_streamable<N,T,typename imp::hexdump_tohex,typename imp::hexdump_toprintable>
252  hexdump( T begin , T end ,
253  unsigned int address_width ,
254  const char * prefix , const char * space , const char * bar ,
255  unsigned int width )
256  {
257  return hexdump<N>( begin , end , address_width , prefix , space , bar , width ,
258  imp::hexdump_tohex() , imp::hexdump_toprintable() ) ;
259  }
260 
261  template <int N,typename T> imp::hexdump_streamable<N,T,typename imp::hexdump_tohex,typename imp::hexdump_toprintable>
262  hexdump( T begin , T end ,
263  unsigned int address_width ,
264  const char * prefix , const char * space , const char * bar )
265  {
266  return hexdump<N>( begin , end , address_width , prefix , space , bar , N ) ;
267  }
268 
269  template <int N,typename T> imp::hexdump_streamable<N,T,typename imp::hexdump_tohex,typename imp::hexdump_toprintable>
270  hexdump( T begin , T end ,
271  unsigned int address_width )
272  {
273  return hexdump<N>( begin , end , address_width , "" , " " , " | " ) ;
274  }
275 
276  template <int N,typename T> imp::hexdump_streamable<N,T,typename imp::hexdump_tohex,typename imp::hexdump_toprintable>
277  hexdump( T begin , T end )
278  {
279  return hexdump<N>( begin , end , 6 ) ;
280  }
281 
282  ///< convenience overloads...
283 
284  template <int N, typename T> imp::hexdump_streamable<N,typename T::const_iterator,typename imp::hexdump_tohex, typename imp::hexdump_toprintable>
285  hexdump( const T & seq )
286  {
287  return hexdump<N,typename T::const_iterator>( seq.begin() , seq.end() ) ;
288  }
289 }
290 
291 #endif
An output adaptor to write to std::ostream.
Definition: ghexdump.h:101
Nibble-to-hex-digit functor.
Definition: ghexdump.h:42
Char-to-printable-ascii functor.
Definition: ghexdump.h:47
void hex_dump(std::ostream &out, T begin, T end, unsigned int address_width, const char *prefix, const char *space, const char *bar, unsigned int width, Ttohex tohex, Ttoprintable toprintable)
Performs a hex dump to the given stream.
Definition: ghexdump.h:178
A streamable class used by G::hexdump().
Definition: ghexdump.h:131
imp::hexdump_streamable< N, T, Ttohex, Ttoprintable > hexdump(T begin, T end, unsigned int address_width, const char *prefix, const char *space, const char *bar, unsigned int width, Ttohex tohex, Ttoprintable toprintable)
Returns a streamable object that does a hex dump.
Definition: ghexdump.h:240