--- parser3/src/classes/math.C 2009/01/23 03:45:18 1.54 +++ parser3/src/classes/math.C 2012/03/16 09:24:07 1.59 @@ -1,22 +1,20 @@ /** @file Parser: @b math parser class. - Copyright(c) 2001-2005 ArtLebedev Group(http://www.artlebedev.com) + Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) portions from gen_uuid.c, Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. */ -static const char * const IDENT_MATH_C="$Date: 2009/01/23 03:45:18 $"; - #include "pa_vmethod_frame.h" #include "pa_common.h" #include "pa_vint.h" #include "pa_vmath.h" #include "pa_request.h" #include "pa_md5.h" -#include "pa_threads.h" +#include "pa_random.h" #ifdef WIN32 # define _WIN32_WINNT 0x400 @@ -32,6 +30,8 @@ static const char * const IDENT_MATH_C=" extern char *crypt(const char* , const char* ); #endif +volatile const char * IDENT_MATH_C="$Id: math.C,v 1.59 2012/03/16 09:24:07 moko Exp $"; + // defines #define MAX_SALT 8 @@ -50,119 +50,8 @@ public: // Methoded DECLARE_CLASS_VAR(math, 0 /*fictive*/, new MMath); -#ifdef WIN32 -class Random_provider { - HCRYPTPROV fhProv; - - void acquire() { - SYNCHRONIZED; - - if(fhProv) - return; - - if(!CryptAcquireContext(&fhProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - throw Exception(0, - 0, - "CryptAcquireContext failed"); - } - void release() { - if(fhProv) - CryptReleaseContext(fhProv, 0); - } - -public: - Random_provider(): fhProv(0) {} - ~Random_provider() { release(); } - void generate(void *buffer, size_t size) { - acquire(); - - if(!CryptGenRandom(fhProv, size, (BYTE*)buffer)) - throw Exception(0, - 0, - "CryptGenRandom failed"); - } -} - random_provider; - -#else - -/// from gen_uuid.c -static int get_random_fd(void) -{ - struct timeval tv; - static int fd = -2; - int i; - - if (fd == -2) { - gettimeofday(&tv, 0); - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) - fd = open("/dev/random", O_RDONLY | O_NONBLOCK); - srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); - } - /* Crank the random number generator a few times */ - gettimeofday(&tv, 0); - for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) - rand(); - return fd; -} - - -/* - * Generate a series of random bytes. Use /dev/urandom if possible, - * and if not, use srandom/random. - */ -static void get_random_bytes(void *buf, int nbytes) -{ - int i, fd = get_random_fd(); - int lose_counter = 0; - char *cp = (char *) buf; - - if (fd >= 0) { - while (nbytes > 0) { - i = read(fd, cp, nbytes); - if (i <= 0) { - if (lose_counter++ > 16) - break; - continue; - } - nbytes -= i; - cp += i; - lose_counter = 0; - } - } - - /* XXX put something better here if no /dev/random! */ - for (i = 0; i < nbytes; i++) - *cp++ = rand() & 0xFF; - return; -} - - -#endif - - -// helpers - -static void random(void *buffer, size_t size) { -#ifdef WIN32 - random_provider.generate(buffer, size); -#else - get_random_bytes(buffer, size); -#endif -} - - // methods -#define MAX_UINT 0xFFFFFFFFu - -static inline int _random(uint top) { - uint raw; - random(&raw, sizeof(raw)); - return int(double(raw) / MAX_UINT * top ); -} - static void _random(Request& r, MethodParams& params) { double top=params.as_double(0, "range must be expression", r); if(top<=0 || top>MAX_UINT) @@ -425,9 +314,10 @@ static void _sha1(Request& r, MethodPara if(!SHA1Result(&c)) throw Exception (PARSER_RUNTIME, 0, "Can not compute SHA1"); - size_t sha1_bufsize=40+/*for zero-teminator*/+1/*for faulty snprintfs*/; - char *sha1_cstr=new(PointerFreeGC) char[sha1_bufsize]; - snprintf(sha1_cstr, sha1_bufsize, + const size_t bufsize=40+1/*zero-teminator*/+1/*for faulty snprintfs*/; + char* cstr=new(PointerFreeGC) char[bufsize]; + + snprintf(cstr, bufsize, "%08x%08x%08x%08x%08x", c.Message_Digest[0], c.Message_Digest[1], @@ -435,51 +325,23 @@ static void _sha1(Request& r, MethodPara c.Message_Digest[3], c.Message_Digest[4]); - r.write_pass_lang(*new String(sha1_cstr)); + r.write_pass_lang(*new String(cstr)); } - -/// to hell with extra bytes on 64bit platforms -struct uuid { - unsigned int time_low; - unsigned short time_mid; - unsigned short time_hi_and_version; - unsigned short clock_seq; - unsigned char node[6]; -}; static void _uuid(Request& r, MethodParams& /*params*/) { + uuid uuid=get_uuid(); - // random - struct uuid uuid; - random(&uuid, sizeof(uuid)); - - // http://www.opengroup.org/onlinepubs/9629399/apdxa.htm#tagtcjh_35 - // ~ - // version = DCE Security version, with embedded POSIX UIDs. - // variant = DCE - // - // DCE=Distributed Computing Environment - // http://www.opengroup.org/dce/ - // - // they say this influences comparison&such, - // but could not figure out how, hence structure layout specified strictly - // anyhow, uuidgen on Win32 yield those values - // - // xxxxxxxx-xxxx-4xxx-{8,9,A,B}xxx-xxxxxxxxxxxx - uuid.clock_seq = (uuid.clock_seq & 0x3FFF) | 0x8000; - uuid.time_hi_and_version = (uuid.time_hi_and_version & 0x0FFF) | 0x4000; - - // format - const int uuid_cstr_bufsize=36+1/*for zero-teminator*/+1/*for faulty snprintfs*/; - char *uuid_cstr=new(PointerFreeGC) char[uuid_cstr_bufsize]; - snprintf(uuid_cstr, uuid_cstr_bufsize, - "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, - uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, - uuid.node[0], uuid.node[1], uuid.node[2], - uuid.node[3], uuid.node[4], uuid.node[5]); + const size_t bufsize=36+1/*zero-teminator*/+1/*for faulty snprintfs*/; + char* cstr=new(PointerFreeGC) char[bufsize]; - r.write_pass_lang(*new String(uuid_cstr)); + snprintf(cstr, bufsize, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); + + r.write_pass_lang(*new String(cstr)); } static void _uid64(Request& r, MethodParams& /*params*/) { @@ -495,6 +357,43 @@ static void _crc32(Request& r, MethodPar r.write_no_lang(*new VInt(pa_crc32(string, strlen(string)))); } +static void toBase(long value, int base, char*& ptr){ + static const char* hex="0123456789ABCDEF"; + int rest = value % base; + if(value >= base) + toBase( (value-rest)/base, base, ptr); + *ptr++=(char)hex[rest]; +} + +static void _convert(Request& r, MethodParams& params) { + const char *string=params.as_string(0, PARAMETER_MUST_BE_STRING).cstr(); + int base_from=params.as_int(1, "base from must be integer", r); + if(base_from < 2 || base_from > 16) + throw Exception(PARSER_RUNTIME, 0, "base from must be an integer from 2 to 16"); + + char *error_pos; + long value=strtol(string, &error_pos, base_from); + while(char c=*error_pos++) + if(!isspace((unsigned char)c)) + throw Exception("number.format", + 0, + "'%s' is invalid number (int)", string); + + int base_to=params.as_int(2, "base to must be integer", r); + if(base_to < 2 || base_to > 16) + throw Exception(PARSER_RUNTIME, 0, "base to must be an integer from 2 to 16"); + + char result_cstr[sizeof(long)*8+1/*minus for negative number*/+1/*terminator*/]; + char* ptr=(char *)&result_cstr; + if(value < 0){ + *ptr++='-'; + value=-value; + } + toBase(value, base_to, ptr); + *ptr=0; + r.write_pass_lang(*new String(pa_strdup(result_cstr))); +} + // constructor MMath::MMath(): Methoded("math") { @@ -537,4 +436,7 @@ MMath::MMath(): Methoded("math") { // ^math:uid64[] ADD0(uid64); + + // ^math:convert[number](base-from;base-to) + add_native_method("convert", Method::CT_STATIC, _convert, 3, 3); }