test/basex.c

00001 /*
00002  * $Id$
00003  *
00004  * Tests for basex.h
00005  *
00006  * Copyright (C) 2008 iptelorg GmbH
00007  *
00008  * Permission to use, copy, modify, and distribute this software for any
00009  * purpose with or without fee is hereby granted, provided that the above
00010  * copyright notice and this permission notice appear in all copies.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00013  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00014  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00015  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00016  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00017  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00018  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00019  */
00020 
00021 
00022 /*#define NO_BASE64_LOOKUP_TABLE
00023  #define SINGLE_REG */
00024 
00025 #include "../basex.h"
00026 #include "profile.h"
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <fcntl.h>
00034 #include <errno.h>
00035 #include <string.h>
00036 #include <time.h>
00037 #include <ctype.h>
00038 
00039 
00040 #ifndef MIN
00041 #define MIN(a,b) (((a)<(b))?(a):(b))
00042 #endif
00043 
00044 #define BASE64 64
00045 #define Q_BASE64 640
00046 #define BASE16 16
00047 
00048 #ifndef BASEX
00049 #define BASEX BASE16
00050 #endif
00051 
00052 #if BASEX == Q_BASE64
00053 
00054 #warning Q_BASE64
00055 #define B_ENC   q_base64_enc
00056 #define B_DEC   q_base64_dec
00057 #define B_ENC_LEN(l)    (((l)+2)/3*4)
00058 
00059 #elif BASEX == BASE16
00060 
00061 #warning BASE16
00062 #define B_ENC   base16_enc
00063 #define B_DEC   base16_dec
00064 #define B_ENC_LEN(l)    ((l)*2)
00065 
00066 #else
00067 
00068 #warning BASE64
00069 #define B_ENC   base64_enc
00070 #define B_DEC   base64_dec
00071 #define B_ENC_LEN(l)    (((l)+2)/3*4)
00072 
00073 
00074 #endif
00075 
00076 
00077 #define QUOTE_MACRO(x) QUOTEME(x)
00078 #define QUOTEME(x) #x
00079 
00080 static char* id="$Id$";
00081 static char* version="basex test 0.1 " 
00082 "BASE" QUOTE_MACRO(BASEX)  ": " QUOTE_MACRO(B_ENC) ", " QUOTE_MACRO(B_DEC) ""
00083 #if defined BASE64_LOOKUP_TABLE 
00084 #ifdef BASE64_LOOKUP_LARGE
00085 " (large b64 lookup table)"
00086 #else
00087 " (lookup b64 table)"
00088 #endif
00089 #else
00090 " (no b64 lookup table)"
00091 #endif
00092 #if defined BASE16_LOOKUP_TABLE
00093 #ifdef BASE16_LOOKUP_LARGE
00094 " (large b16 lookup table)"
00095 #else
00096 " (lookup b16 table)"
00097 #endif
00098 #else
00099 " (no b16 lookup table)"
00100 #endif
00101 #if defined BASE64_READ_WHOLE_INTS || defined BASE16_READ_WHOLE_INTS
00102 " (read 4 bytes at a time)"
00103 #else
00104 " (read 1 byte at a time)"
00105 #endif
00106 ;
00107 
00108 static char* help_msg="\
00109 Usage: basex  [-hv] ... [options]\n\
00110 Options:\n\
00111     -m min        minimum length\n\
00112     -M max        maximum length\n\
00113     -o offset     offset from the start of the buffer (alignment tests)\n\
00114     -e offset     offset from the start of the dst. buf. (alignment tests)\n\
00115     -n no.        number of test loops\n\
00116     -v            increase verbosity\n\
00117     -V            version number\n\
00118     -h            this help message\n\
00119 ";
00120 
00121 
00122 /* profiling */
00123 struct profile_data pf1, pf2, pf3, pf4, pf5, pf6;
00124 
00125 
00126 void dump_profile_info(struct profile_data* pd)
00127 {
00128         printf("profiling for %s (%ld/%ld):  %lld/%lld/%lld (max/avg/last),"
00129                         " total %lld\n",
00130                         pd->name, pd->entries, pd->exits, pd->max_cycles, 
00131                         pd->entries?pd->total_cycles/pd->entries:0, pd->cycles,
00132                         pd->total_cycles);
00133 }
00134 
00135 
00136 
00137 int seed_prng()
00138 {
00139         int seed, rfd;
00140         
00141         if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
00142 try_again:
00143                 if (read(rfd, (void*)&seed, sizeof(seed))==-1){
00144                         if (errno==EINTR) goto try_again; /* interrupted by signal */
00145                                 fprintf(stderr, "WARNING: could not read from /dev/urandom: "
00146                                                                 " %s (%d)\n", strerror(errno), errno);
00147                 }
00148                 close(rfd);
00149         }else{
00150                 fprintf(stderr, "WARNING: could not open /dev/urandom: %s (%d)\n",
00151                                                 strerror(errno), errno);
00152         }
00153         seed+=getpid()+time(0);
00154         srand(seed);
00155         return 0;
00156 }
00157 
00158 
00159 /* fill buf with random data*/
00160 void fill_rand(unsigned char* buf, int len)
00161 {
00162         unsigned char* end;
00163         int v;
00164 
00165 /* find out how many random bytes we can get from rand() */
00166 #if RAND_MAX >= 0xffffffff
00167 #define RAND_BYTES 4
00168 #warning RAND_BYTES is 4
00169 #elif RAND_MAX >= 0xffffff
00170 #define RAND_BYTES 3
00171 #warning RAND_BYTES is 3
00172 #elif RAND_MAX >= 0xffff
00173 #define RAND_BYTES 2
00174 #warning RAND_BYTES is 2
00175 #else
00176 #define RAND_BYTES 1
00177 #endif
00178 
00179         end=buf+len/RAND_BYTES*RAND_BYTES;
00180         for(;buf<end;buf+=RAND_BYTES){
00181                 v=rand();
00182                 buf[0]=v;
00183 #if RAND_BYTES > 1
00184                 buf[1]=v>>8;
00185 #endif
00186 #if RAND_BYTES > 2
00187                 buf[2]=v>>16;
00188 #endif
00189 #if RAND_BYTES > 4
00190                 buf[3]=v>>24;
00191 #endif
00192         }
00193         v=rand();
00194         switch(end-buf){
00195                 case 3:
00196 #if RAND_BYTES > 2
00197                         buf[2]=v>>16;
00198 #else
00199                         buf[2]=rand();
00200 #endif
00201                 case 2:
00202 #if RAND_BYTES > 1
00203                         buf[1]=v>>8;
00204 #else
00205                         buf[1]=rand();
00206 #endif
00207                 case 1:
00208                         buf[0]=v;
00209                 case 0:
00210                         break;
00211         }
00212 }
00213 
00214 
00215 
00216 int main(int argc, char** argv)
00217 {
00218 
00219         int loops, min_len, max_len, offset, e_offset;
00220         unsigned char* ibuf;
00221         unsigned char* enc_buf;
00222         unsigned char* dec_buf;
00223         int ibuf_len, enc_buf_len, dec_buf_len;
00224         int offs, c_len, e_len, l;
00225         int r;
00226         int verbose;
00227         int c;
00228         char* tmp;
00229 
00230         verbose=0;
00231         min_len=max_len=offset=-1;
00232         e_offset=0;
00233         loops=1024;
00234         opterr=0;
00235         while ((c=getopt(argc, argv, "n:m:M:o:e:vhV"))!=-1){
00236                 switch(c){
00237                         case 'n':
00238                                 loops=strtol(optarg, &tmp, 0);
00239                                 if ((tmp==0)||(*tmp)||(loops<0)){
00240                                         fprintf(stderr, "bad number: -%c %s\n", c, optarg);
00241                                         goto error;
00242                                 }
00243                                 break;
00244                         case 'm':
00245                                 min_len=strtol(optarg, &tmp, 0);
00246                                 if ((tmp==0)||(*tmp)||(min_len<0)){
00247                                         fprintf(stderr, "bad number: -%c %s\n", c, optarg);
00248                                         goto error;
00249                                 }
00250                                 break;
00251                         case 'M':
00252                                 max_len=strtol(optarg, &tmp, 0);
00253                                 if ((tmp==0)||(*tmp)||(max_len<0)){
00254                                         fprintf(stderr, "bad number: -%c %s\n", c, optarg);
00255                                         goto error;
00256                                 }
00257                                 break;
00258                         case 'o':
00259                                 offset=strtol(optarg, &tmp, 0);
00260                                 if ((tmp==0)||(*tmp)||(offset<0)){
00261                                         fprintf(stderr, "bad number: -%c %s\n", c, optarg);
00262                                         goto error;
00263                                 }
00264                                 break;
00265                         case 'e':
00266                                 e_offset=strtol(optarg, &tmp, 0);
00267                                 if ((tmp==0)||(*tmp)||(e_offset<0)){
00268                                         fprintf(stderr, "bad number: -%c %s\n", c, optarg);
00269                                         goto error;
00270                                 }
00271                                 break;
00272                         case 'v':
00273                                 verbose++;
00274                                 break;
00275                         case 'V':
00276                                 printf("version: %s\n", version);
00277                                 printf("%s\n", id);
00278                                 exit(0);
00279                                 break;
00280                         case 'h':
00281                                 printf("version: %s\n", version);
00282                                 printf("%s", help_msg);
00283                                 exit(0);
00284                                 break;
00285                         case '?':
00286                                 if (isprint(optopt))
00287                                         fprintf(stderr, "Unknown option `-%c\n", optopt);
00288                                 else
00289                                         fprintf(stderr, "Unknown character `\\x%x\n", optopt);
00290                                 goto error;
00291                         case ':':
00292                                 fprintf(stderr, "Option `-%c requires an argument.\n",
00293                                                 optopt);
00294                                 goto error;
00295                                 break;
00296                         default:
00297                                 abort();
00298                 }
00299         }
00300         if (min_len==-1 && max_len==-1){
00301                 min_len=0;
00302                 max_len=4*1024*1024;
00303         }else if (min_len==-1)
00304                 min_len=0;
00305         else if (max_len==-1)
00306                 max_len=min_len;
00307         /* init */
00308         ibuf_len=max_len;
00309         ibuf=malloc(ibuf_len);
00310         if (ibuf==0){
00311                 fprintf(stderr, "ERROR: 1. memory allocation error (%d bytes)\n",
00312                                                 ibuf_len);
00313                 exit(-1);
00314         }
00315         enc_buf_len=B_ENC_LEN(ibuf_len);
00316         enc_buf=malloc(enc_buf_len+e_offset);
00317         if (enc_buf==0){
00318                 fprintf(stderr, "ERROR: 2. memory allocation error (%d bytes)\n",
00319                                                 enc_buf_len);
00320                 exit(-1);
00321         }
00322         enc_buf+=e_offset; /* make sure it's off by e_offset bytes from the
00323                                                  aligned stuff malloc returns */
00324         dec_buf_len=ibuf_len;
00325         dec_buf=malloc(dec_buf_len+e_offset);
00326         if (dec_buf==0){
00327                 fprintf(stderr, "ERROR: 3. memory allocation error (%d bytes)\n",
00328                                                 dec_buf_len+e_offset);
00329                 exit(-1);
00330         }
00331         dec_buf+=e_offset; /* make sure it's off by e_offset bytes from the
00332                                                   aligned stuff malloc returns */
00333         
00334         
00335         seed_prng();
00336         /* profile */
00337         profile_init(&pf1, "encode");
00338         profile_init(&pf2, "decode");
00339         
00340         init_basex();
00341         if (verbose)
00342                 printf("starting (loops %d, min size %d, max size %d, offset %d,"
00343                                 ", e_offset %d, buffer sizes %d %d %d)\n",
00344                                 loops, min_len, max_len, offset, e_offset, ibuf_len,
00345                                 enc_buf_len, dec_buf_len);
00346                 
00347                 for (r=0; r<loops; r++){
00348                         if (min_len!=max_len)
00349                                 /* test encode/decode random data w/ random length*/
00350                                 c_len= min_len+(int)((float)(max_len-min_len+1)*
00351                                                                                         (rand()/(RAND_MAX+1.0)));
00352                         else 
00353                                 /* test encode /decode random data w/ fixed lenght*/
00354                                 c_len=max_len;
00355                         if (offset==-1)
00356                                 /* offset between 0 & MIN(clen,3) */
00357                                 offs= (int)((float)(MIN(c_len,3)+1)*(rand()/(RAND_MAX+1.0)));
00358                         else if (offset>c_len)
00359                                 offs=0;
00360                         else
00361                                 offs=offset;
00362                         if (verbose>2)
00363                                 printf("loop %d, current len %d, offset %d, start %p\n",
00364                                                         r, c_len-offs, offs, &ibuf[offs]);
00365                         else if ((verbose >1) && (r %10==0)) putchar('.');
00366                         
00367                         fill_rand(ibuf, c_len);
00368                         
00369                         c_len-=offs;
00370                         e_len=B_ENC_LEN(c_len);
00371                         profile_start(&pf1);
00372                         l=B_ENC(&ibuf[offs], c_len, enc_buf, e_len);
00373                         profile_end(&pf1);
00374                         if (l != e_len){
00375                                 fprintf(stderr, "ERROR: invalid length for encoding: %d "
00376                                                                 "instead of %d (loops=%d)\n", l, e_len, r);
00377                                 exit(-1);
00378                         }
00379                         profile_start(&pf2);
00380                         l=B_DEC(enc_buf, e_len, dec_buf, c_len);
00381                         profile_end(&pf2);
00382                         if (l != c_len){
00383                                 fprintf(stderr, "ERROR: invalid length for decoding: %d "
00384                                                                 "instead of %d (loops=%d)\n", l, c_len, r);
00385                                 exit(-1);
00386                         }
00387                         if (memcmp(&ibuf[offs], dec_buf, c_len)!=0){
00388                                 fprintf(stderr, "ERROR: decoding mismatch "
00389                                                                 "(loops=%d, c_len=%d)\n", r, c_len);
00390                                 abort();
00391                                 exit(-1);
00392                         }
00393                 }
00394          if (verbose >1) putchar('\n');
00395         /* encode len data and decode it, print profiling info*/
00396          dump_profile_info(&pf1);
00397          dump_profile_info(&pf2);
00398          return 0;
00399 error:
00400                  exit(-1);
00401 }