gnuworld/include/Numeric.h

191 lines
5.8 KiB
C++

/**
* Numeric.h
* This file contains basic routines for converting numerics between
* integer and char* and std::string formats.
* The majority of this code is from the Undernet ircu code base.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*
* $Id: Numeric.h,v 1.7 2009/07/26 18:30:37 mrbean_ Exp $
*/
#ifndef __NUMERIC_H
#define __NUMERIC_H "$Id: Numeric.h,v 1.7 2009/07/26 18:30:37 mrbean_ Exp $"
/*
* Numeric nicks are new as of version ircu2.10.00beta1.
*
* The idea is as follows:
* In most messages (for protocol 10+) the original nick will be
* replaced by a 3 character string: YXX
* Where 'Y' represents the server, and 'XX' the nick on that server.
*
* 'YXX' should not interfer with the input parser, and therefore is
* not allowed to contain spaces or a ':'.
* Also, 'Y' can't start with a '+' because of m_server().
*
* We keep the characters printable for debugging reasons too.
*
* The 'XX' value can be larger then the maximum number of clients
* per server, we use a mask (struct Server::nn_mask) to get the real
* client numeric. The overhead is used to have some redundancy so
* just-disconnected-client aren't confused with just-connected ones.
*/
/* These must be the same on ALL servers ! Do not change ! */
#include <cassert>
namespace gnuworld
{
/// The length of the character numerics, 5 for n2k
#define P10_NUMNICKLEN 5
#define NUMNICKLOG 6
#define NUMNICKMAXCHAR 'z' /* See convert2n[] */
#define NUMNICKBASE 64 /* (2 << NUMNICKLOG) */
#define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
#define NN_MAX_SERVER 4096 /* (NUMNICKBASE * NUMNICKBASE) */
/*
* The internal counter for the 'XX' of local clients
*/
/**
* convert2y[] converts a numeric to the corresponding character.
* The following characters are currently known to be forbidden:
*
* '\0' : Because we use '\0' as end of line.
*
* ' ' : Because parse_*() uses this as parameter seperator.
* ':' : Because parse_server() uses this to detect if a prefix is a
* numeric or a name.
* '+' : Because m_nick() uses this to determine if parv[6] is a
* umode or not.
* '&', '#', '+', '$', '@' and '%' :
* Because m_message() matches these characters to detect special cases.
*/
static const char convert2y[] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
};
/**
* convert2n[] ocnverts a character to the corresponding integer.
*/
static const unsigned int convert2n[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/**
* This method converts a base64 character array to
* an unsigned integer.
*/
inline unsigned int base64toint( const char* s )
{
unsigned int i = convert2n[ static_cast< unsigned char >( *s++ ) ] ;
while( *s )
{
i <<= NUMNICKLOG;
i += convert2n[ static_cast< unsigned char >( *s++ ) ] ;
}
return i ;
}
/**
* This method converts only the first (count) characters
* of the string (s) to unsigned integer format.
*/
inline unsigned int base64toint( const char* s, size_t count )
{
assert( s != 0 ) ;
unsigned int i = convert2n[ static_cast< unsigned char >( *s++ ) ] ;
while (*s && --count > 0)
{
i <<= NUMNICKLOG;
i += convert2n[ static_cast< unsigned char >( *s++ ) ] ;
}
return i;
}
/**
* This method converts an unsigned integer (v) to a base64
* character array of length (count).
* Be sure that buf is allocated and large enough to hold
* (count) characters (excluding null terminator).
* This method returns a pointer to the base 64 buffer.
*/
inline const char* inttobase64( char* buf, unsigned int v, size_t count )
{
assert( buf != 0 ) ;
buf[count] = '\0';
while (count > 0)
{
buf[ --count ] = convert2y[(v & NUMNICKMASK)];
v >>= NUMNICKLOG;
}
return buf;
}
inline void splitbase64int( unsigned int intYYXXX,
unsigned int& intYY,
unsigned int& intXXX )
{
// Decompose to charYYXXX
char charYYXXX[ 6 ] ;
inttobase64( charYYXXX, intYYXXX, 5 ) ;
// Now split the charYYXXX into two ints
intYY = base64toint( charYYXXX, 2 ) ;
intXXX = base64toint( &charYYXXX[ 2 ], 3 ) ;
}
inline unsigned int combinebase64int( const unsigned int& intYY,
const unsigned int& intXXX )
{
char charYYXXX[ 6 ] ;
inttobase64( charYYXXX, intYY, 2 ) ;
inttobase64( &charYYXXX[ 2 ], intXXX, 3 ) ;
return base64toint( charYYXXX, 5 ) ;
}
} // namespace gnuworld
#endif // __NUMERIC_H