Enclosed patch adds md5() as an aggregate. Unit tests refactored to use md5() as opposed to md5sum(). All tests pass [that did before].

I broke the core md5 functions out into a header file full of static inlines. This reduces namespace pollution while still allowing the same code to be used by both the Tcl test code and the core sqlite implementation.

Index: Makefile.in
===================================================================
RCS file: /sqlite/sqlite/Makefile.in,v
retrieving revision 1.80
diff -r1.80 Makefile.in
133c133,134
< $(TOP)/src/where.c
---
> $(TOP)/src/where.c \
> $(TOP)/src/md5.h
146c147
< $(TOP)/src/md5.c
---
> $(TOP)/src/md5test.c
478c479
<
---
>
Index: src/func.c
===================================================================
RCS file: /sqlite/sqlite/src/func.c,v
retrieving revision 1.38
diff -r1.38 func.c
26a27
> #include "md5.h"
545a547,575
> ** The md5() aggregate function.
> */
> static void md5step(sqlite_func *context, int argc, const char **argv){
> MD5Context *p;
> int i;
> if( argc<1 ) return;
> p = sqlite_aggregate_context(context, sizeof(*p));
> if( p==0 ) return;
> if( sqlite_aggregate_count(context)==1 ){
> MD5Init(p);
> }
> for(i=0; i<argc; i++){
> if( argv[i] ){
> MD5Update(p, (unsigned char*)argv[i], strlen(argv[i]));
> }
> }
> }
>
> static void md5finalize(sqlite_func *context){
> MD5Context *p;
> unsigned char digest[16];
> char zBuf[33];
> p = sqlite_aggregate_context(context, sizeof(*p));
> MD5Final(digest,p);
> DigestToBase16(digest, zBuf);
> sqlite_set_result_string(context, zBuf, strlen(zBuf));
> }
>
> /*
619a650,651
>
> sqlite_create_aggregate(db, "md5", -1, md5step, md5finalize, 0);
Index: src/tclsqlite.c
===================================================================
RCS file: /sqlite/sqlite/src/tclsqlite.c,v
retrieving revision 1.55
diff -r1.55 tclsqlite.c
1089,1097d1088
< /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
< ** SQL function.
< */
< #ifdef SQLITE_TEST
< {
< extern void Md5_Register(sqlite*);
< Md5_Register(p->db);
< }
< #endif
Index: test/bigfile.test
===================================================================
RCS file: /sqlite/sqlite/test/bigfile.test,v
retrieving revision 1.3
diff -r1.3 bigfile.test
48c48
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
66c66
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
80c80
< SELECT md5sum(x) FROM t2;
---
> SELECT md5(x) FROM t2;
87c87
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
92c92
< SELECT md5sum(x) FROM t2;
---
> SELECT md5(x) FROM t2;
106c106
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
112c112
< SELECT md5sum(x) FROM t3;
---
> SELECT md5(x) FROM t3;
119c119
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
124c124
< SELECT md5sum(x) FROM t2;
---
> SELECT md5(x) FROM t2;
129c129
< SELECT md5sum(x) FROM t3;
---
> SELECT md5(x) FROM t3;
143c143
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
149c149
< SELECT md5sum(x) FROM t4;
---
> SELECT md5(x) FROM t4;
156c156
< SELECT md5sum(x) FROM t1;
---
> SELECT md5(x) FROM t1;
161c161
< SELECT md5sum(x) FROM t2;
---
> SELECT md5(x) FROM t2;
166c166
< SELECT md5sum(x) FROM t3;
---
> SELECT md5(x) FROM t3;
171c171
< SELECT md5sum(x) FROM t3;
---
> SELECT md5(x) FROM t3;
Index: test/memdb.test
===================================================================
RCS file: /sqlite/sqlite/test/memdb.test,v
retrieving revision 1.6
diff -r1.6 memdb.test
64c64
< # set r [db eval {SELECT count(*), md5sum(x) FROM t3}]
---
> # set r [db eval {SELECT count(*), md5(x) FROM t3}]
Index: test/trans.test
===================================================================
RCS file: /sqlite/sqlite/test/trans.test,v
retrieving revision 1.18
diff -r1.18 trans.test
687c687
< set ::checksum [execsql {SELECT md5sum(x,y,z) FROM t2}]
---
> set ::checksum [execsql {SELECT md5(x,y,z) FROM t2}]
689c689
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
694c694
< execsql {SELECT md5sum(x,y,z) FROM t2}
---
> execsql {SELECT md5(x,y,z) FROM t2}
697c697
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
704c704
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
712c712
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
720c720
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
728c728
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
737c737
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
741c741
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
749c749
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
753c753
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
764c764
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
768c768
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
775c775
< SELECT md5sum(x,y,z) FROM t2;
---
> SELECT md5(x,y,z) FROM t2;
779c779
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
801c801
< execsql {SELECT md5sum(x,y,z) FROM t2}
---
> execsql {SELECT md5(x,y,z) FROM t2}
804c804
< execsql {SELECT md5sum(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
---
> execsql {SELECT md5(type,name,tbl_name,rootpage,sql) FROM sqlite_master}
845c845
< return [db eval {SELECT count(*), md5sum(x) FROM t3}]
---
> return [db eval {SELECT count(*), md5(x) FROM t3}]



This is the file src/md5.h: /* * If compiled on a machine that doesn't have a 32-bit integer, * you just set "uint32" to the appropriate datatype for an * unsigned 32-bit integer. For example: * * cc -Duint32='unsigned long' md5.c * */ #ifndef uint32 # define uint32 unsigned int #endif

struct Context {
  uint32 buf[4];
  uint32 bits[2];
  unsigned char in[64];
};
typedef char MD5Context[88];

/*
 * Note: this code is harmless on little-endian machines.
 */
static inline void byteReverse (unsigned char *buf, unsigned longs){
        uint32 t;
        do {
                t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
                            ((unsigned)buf[1]<<8 | buf[0]);
                *(uint32 *)buf = t;
                buf += 4;
        } while (--longs);
}
/* The four core functions - F1 is optimized somewhat */

/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
static inline void MD5Transform(uint32 buf[4], const uint32 in[16]){
        register uint32 a, b, c, d;

        a = buf[0];
        b = buf[1];
        c = buf[2];
        d = buf[3];

        MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
        MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
        MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
        MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
        MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
        MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
        MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
        MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
        MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
        MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
        MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
        MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
        MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
        MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
        MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
        MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);

        MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
        MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
        MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
        MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
        MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
        MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
        MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
        MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
        MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
        MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
        MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
        MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
        MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
        MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
        MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
        MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);

        MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
        MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
        MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
        MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
        MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
        MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
        MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
        MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
        MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
        MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
        MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
        MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
        MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
        MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
        MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
        MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);

        MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
        MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
        MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
        MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
        MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
        MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
        MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
        MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
        MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
        MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
        MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
        MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
        MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
        MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
        MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
        MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);

        buf[0] += a;
        buf[1] += b;
        buf[2] += c;
        buf[3] += d;
}

/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
static inline void MD5Init(MD5Context *pCtx){
        struct Context *ctx = (struct Context *)pCtx;
        ctx->buf[0] = 0x67452301;
        ctx->buf[1] = 0xefcdab89;
        ctx->buf[2] = 0x98badcfe;
        ctx->buf[3] = 0x10325476;
        ctx->bits[0] = 0;
        ctx->bits[1] = 0;
}

/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static inline
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
struct Context *ctx = (struct Context *)pCtx;
uint32 t;


/* Update bitcount */

        t = ctx->bits[0];
        if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
                ctx->bits[1]++; /* Carry from low to high */
        ctx->bits[1] += len >> 29;

t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */

/* Handle any leading odd-sized chunks */

        if ( t ) {
                unsigned char *p = (unsigned char *)ctx->in + t;

                t = 64-t;
                if (len < t) {
                        memcpy(p, buf, len);
                        return;
                }
                memcpy(p, buf, t);
                byteReverse(ctx->in, 16);
                MD5Transform(ctx->buf, (uint32 *)ctx->in);
                buf += t;
                len -= t;
        }

/* Process data in 64-byte chunks */

        while (len >= 64) {
                memcpy(ctx->in, buf, 64);
                byteReverse(ctx->in, 16);
                MD5Transform(ctx->buf, (uint32 *)ctx->in);
                buf += 64;
                len -= 64;
        }

/* Handle any remaining bytes of data. */

        memcpy(ctx->in, buf, len);
}

/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
static inline void MD5Final(unsigned char digest[16], MD5Context *pCtx){
        struct Context *ctx = (struct Context *)pCtx;
        unsigned count;
        unsigned char *p;

        /* Compute number of bytes mod 64 */
        count = (ctx->bits[0] >> 3) & 0x3F;

/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = ctx->in + count;
*p++ = 0x80;


        /* Bytes of padding needed to make 64 bytes */
        count = 64 - 1 - count;

/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32 *)ctx->in);


                /* Now fill the next block with 56 bytes */
                memset(ctx->in, 0, 56);
        } else {
                /* Pad block to 56 bytes */
                memset(p, 0, count-8);
        }
        byteReverse(ctx->in, 14);

        /* Append length in bits and transform */
        ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
        ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];

        MD5Transform(ctx->buf, (uint32 *)ctx->in);
        byteReverse((unsigned char *)ctx->buf, 4);
        memcpy(digest, ctx->buf, 16);
        memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
}

/*
** Convert a digest into base-16.  digest should be declared as
** "unsigned char digest[16]" in the calling function.  The MD5
** digest is stored in the first 16 bytes.  zBuf should
** be "char zBuf[33]".
*/
static inline void DigestToBase16(unsigned char *digest, char *zBuf){
  static char const zEncode[] = "0123456789abcdef";
  int i, j;

  for(j=i=0; i<16; i++){
    int a = digest[i];
    zBuf[j++] = zEncode[(a>>4)&0xf];
    zBuf[j++] = zEncode[a & 0xf];
  }
  zBuf[j] = 0;
}


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to