E-MailRelay
ghashstate.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
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 ghashstate.h
19///
20
21#ifndef G_HASH_STATE_H
22#define G_HASH_STATE_H
23
24#include "gdef.h"
25#include <string>
26#include <array>
27
28namespace G
29{
30 class HashStateImp ;
31 template <unsigned int N, typename U, typename S> class HashState ;
32}
33
34//| \class G::HashStateImp
35/// The non-template part of G::HashState.
36///
38{
39public:
40 template <typename U> static std::string extension( U n ) ;
41 ///< Returns the given data size as a four-character
42 ///< string.
43
44protected:
45 template <typename U> static void convert_( U n , std::string::iterator p ) ;
46 ///< Encodes the given value into four characters.
47
48public:
49 HashStateImp() = delete ;
50} ;
51
52//| \class G::HashState
53/// Functions for representing the intermediate state of a hash function
54/// as a non-printable string. The input is an array of 'N/4' 32-bit
55/// values. The output is a string of N non-printable characters, or N+4
56/// characters if also including the data size. The 'U' type can be more
57/// than 32 bits wide but it should hold values of no more than 32 bits
58/// significance.
59/// \see G::Hash::printable
60///
61template <unsigned int N, typename U, typename S>
63{
64public:
65 using uint_type = U ;
66 using size_type = S ;
67 static_assert( N != 0 && (N%4) == 0 , "hash state size must be a multiple of four" ) ;
68
69 static std::string encode( const uint_type * ) ;
70 ///< Returns the hash state as an N-character string of
71 ///< non-printing characters.
72
73 static std::string encode( const uint_type * , size_type n ) ;
74 ///< Returns the hash state as a string that also
75 ///< has the original data size as a four-character
76 ///< extension().
77
78 static std::string encode( uint_type hi , uint_type low , const uint_type * ) ;
79 ///< An overload with a hi/low bit count.
80
81 static std::string encode( uint_type hi , uint_type low , uint_type v0 , uint_type v1 ,
82 uint_type v2 , uint_type v3 , uint_type v4 = 0 ) ;
83 ///< An overload for N=16 or N=20 with broken-out
84 ///< values and a hi/low bit count.
85
86 static void decode( const std::string & s , uint_type * values_out , size_type & size_out ) ;
87 ///< Converts an encode()d string back into a hash
88 ///< state of N/4 integers and a data size returned
89 ///< by reference. The data size is returned as zero
90 ///< if the input string is only N characters long.
91
92 static void decode( const std::string & , uint_type & size_hi_out , uint_type & size_low_out ,
93 uint_type * value_0 , uint_type * value_1 , uint_type * value_2 , uint_type * value_3 ,
94 uint_type * value_4 = nullptr ) ;
95 ///< An overload for N=16 or N=20 with broken-out
96 ///< values and hi/low bit count.
97
98 static void decode( const std::string & , uint_type & size_hi_out , uint_type & size_low_out ,
99 uint_type * values_out ) ;
100 ///< An overload for a hi/low bit count.
101
102public:
103 HashState() = delete ;
104
105private:
106 static void convert( char hi , char himid , char lomid , char lo , uint_type & n ) ;
107 static void convert( const std::string & str , uint_type & n ) ;
108 static void convert( const std::string & s , uint_type * state ) ;
109 static void convert( const std::string & s , uint_type * state , size_type & ) ;
110} ;
111
112template <unsigned int N, typename U, typename S>
113std::string G::HashState<N,U,S>::encode( const uint_type * values )
114{
115 std::string result( N , '\0' ) ;
116 for( std::size_t i = 0U ; i < N/4 ; i++ )
117 {
118 convert_( values[i] , result.begin() + (i*4U) ) ; // NOLINT narrowing
119 }
120 return result ;
121}
122
123template <unsigned int N, typename U, typename S>
124std::string G::HashState<N,U,S>::encode( const uint_type * values , size_type n )
125{
126 std::string result( N+4U , '\0' ) ;
127 for( std::size_t i = 0U ; i < N/4 ; i++ )
128 {
129 convert_( values[i] , result.begin() + (i*4U) ) ; // NOLINT narrowing
130 }
131 convert_( n , result.begin() + N ) ;
132 return result ;
133}
134
135template <unsigned int N, typename U, typename S>
136std::string G::HashState<N,U,S>::encode( uint_type hi , uint_type low , const uint_type * values )
137{
138 uint_type n = hi ;
139 n <<= 29 ;
140 n |= ( low >> 3 ) ;
141 return encode( values , n ) ;
142}
143
144template <unsigned int N, typename U, typename S>
145std::string G::HashState<N,U,S>::encode( uint_type hi , uint_type low , uint_type v0 ,
146 uint_type v1 , uint_type v2 , uint_type v3 , uint_type v4 )
147{
148 uint_type n = hi ;
149 n <<= 29 ;
150 n |= ( low >> 3 ) ;
151 std::array<uint_type,N/4> values {} ;
152 if( N > 0 ) values[0] = v0 ;
153 if( N > 4 ) values[1] = v1 ;
154 if( N > 8 ) values[2] = v2 ;
155 if( N > 12 ) values[3] = v3 ;
156 if( N > 16 ) values[4] = v4 ;
157 return encode( &values[0] , n ) ;
158}
159
160template <typename U>
162{
163 std::string result( 4U , '\0' ) ;
164 convert_( n , result.begin() ) ;
165 return result ;
166}
167
168template <unsigned int N, typename U, typename S>
169void G::HashState<N,U,S>::decode( const std::string & str , uint_type * values_out , size_type & size_out )
170{
171 if( str.length() < (N+4U) )
172 return decode( str+std::string(N+4U,'\0') , values_out , size_out ) ; // call ourselves again if too short
173 convert( str , values_out , size_out ) ;
174}
175
176template <unsigned int N, typename U, typename S>
177void G::HashState<N,U,S>::decode( const std::string & str , uint_type & hi , uint_type & low ,
178 uint_type * v0 , uint_type * v1 , uint_type * v2 , uint_type * v3 , uint_type * v4 )
179{
180 if( str.length() < (N+4U) ) return decode( str+std::string(N+4U,'\0') , hi , low , v0 , v1 , v2 , v3 , v4 ) ;
181 std::array<uint_type,N/4> values {} ;
182 uint_type n ;
183 convert( str , &values[0] , n ) ;
184 if( v0 && N > 0 ) *v0 = values[0] ;
185 if( v1 && N > 4 ) *v1 = values[1] ;
186 if( v2 && N > 8 ) *v2 = values[2] ;
187 if( v3 && N > 12 ) *v3 = values[3] ;
188 if( v4 && N > 16 ) *v4 = values[4] ;
189 hi = ( n >> 29 ) ;
190 low = ( n << 3 ) & 0xffffffffUL ;
191}
192
193template <unsigned int N, typename U, typename S>
194void G::HashState<N,U,S>::decode( const std::string & str , uint_type & hi , uint_type & low ,
195 uint_type * values_out )
196{
197 if( str.length() < (N+4U) ) return decode( str+std::string(N+4U,'\0') , hi , low , values_out ) ;
198 uint_type n ;
199 convert( str , values_out , n ) ;
200 hi = ( n >> 29 ) ;
201 low = ( n << 3 ) & 0xffffffffUL ;
202}
203
204template <typename U>
205void G::HashStateImp::convert_( U n , std::string::iterator p_out )
206{
207 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
208 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
209 *p_out++ = static_cast<char>(n&0xffU) ; n >>= 8U ;
210 *p_out++ = static_cast<char>(n&0xffU) ;
211}
212
213template <unsigned int N, typename U, typename S>
214void G::HashState<N,U,S>::convert( char hi , char himid , char lomid , char lo , uint_type & n_out )
215{
216 n_out = 0U ;
217 n_out |= static_cast<unsigned char>(hi) ; n_out <<= 8 ;
218 n_out |= static_cast<unsigned char>(himid) ; n_out <<= 8 ;
219 n_out |= static_cast<unsigned char>(lomid) ; n_out <<= 8 ;
220 n_out |= static_cast<unsigned char>(lo) ;
221}
222
223template <unsigned int N, typename U, typename S>
224void G::HashState<N,U,S>::convert( const std::string & str , uint_type & n_out )
225{
226 convert( str.at(3) , str.at(2) , str.at(1) , str.at(0) , n_out ) ;
227}
228
229template <unsigned int N, typename U, typename S>
230void G::HashState<N,U,S>::convert( const std::string & str , uint_type * state_out )
231{
232 for( std::size_t i = 0U ; i < (N/4U) ; i++ )
233 {
234 convert( str.at(i*4U+3U) , str.at(i*4U+2U) , str.at(i*4U+1U) , str.at(i*4U+0U) , state_out[i] ) ;
235 }
236}
237
238template <unsigned int N, typename U, typename S>
239void G::HashState<N,U,S>::convert( const std::string & str , uint_type * state_out , size_type & n_out )
240{
241 convert( str , state_out ) ;
242 uint_type nn = 0 ;
243 convert( str.at(N+3U) , str.at(N+2U) , str.at(N+1U) , str.at(N) , nn ) ;
244 n_out = static_cast<size_type>(nn) ;
245}
246
247#endif
The non-template part of G::HashState.
Definition: ghashstate.h:38
static std::string extension(U n)
Returns the given data size as a four-character string.
Definition: ghashstate.h:161
static void convert_(U n, std::string::iterator p)
Encodes the given value into four characters.
Definition: ghashstate.h:205
Functions for representing the intermediate state of a hash function as a non-printable string.
Definition: ghashstate.h:63
static std::string encode(const uint_type *)
Returns the hash state as an N-character string of non-printing characters.
Definition: ghashstate.h:113
static void decode(const std::string &s, uint_type *values_out, size_type &size_out)
Converts an encode()d string back into a hash state of N/4 integers and a data size returned by refer...
Definition: ghashstate.h:169
Low-level classes.
Definition: galign.h:28