Checksum.cc

Go to the documentation of this file.
00001 
00020 #include "Compat.h"
00021 #include <arpa/inet.h>
00022 #include <zlib.h>
00023 #include "Checksum.h"
00024 
00025 namespace Hypertable {
00026 
00027 #define HT_F32_DO1(buf,i) \
00028   sum1 += ((uint16_t)buf[i] << 8) | buf[i+1]; sum2 += sum1
00029 #define HT_F32_DO2(buf,i)  HT_F32_DO1(buf,i); HT_F32_DO1(buf,i+2);
00030 #define HT_F32_DO4(buf,i)  HT_F32_DO2(buf,i); HT_F32_DO2(buf,i+4);
00031 #define HT_F32_DO8(buf,i)  HT_F32_DO4(buf,i); HT_F32_DO4(buf,i+8);
00032 #define HT_F32_DO16(buf,i) HT_F32_DO8(buf,i); HT_F32_DO8(buf,i+16);
00033 
00034 /* cf. http://en.wikipedia.org/wiki/Fletcher%27s_checksum
00035  */
00036 uint32_t
00037 fletcher32(const void *data8, size_t len8) {
00038   /* data may not be aligned properly and would segfault on
00039    * many systems if cast and used as 16-bit words
00040    */
00041   const uint8_t *data = (const uint8_t *)data8;
00042   uint32_t sum1 = 0xffff, sum2 = 0xffff;
00043   size_t len = len8 / 2; /* loop works on 16-bit words */
00044 
00045   while (len) {
00046     /* 360 is the largest number of sums that can be
00047      * performed without integer overflow
00048      */
00049     unsigned tlen = len > 360 ? 360 : len;
00050     len -= tlen;
00051 
00052     if (tlen >= 16) do {
00053       HT_F32_DO16(data, 0);
00054       data += 32;
00055       tlen -= 16;
00056     } while (tlen >= 16);
00057 
00058     if (tlen != 0) do {
00059       HT_F32_DO1(data, 0);
00060       data += 2;
00061     } while (--tlen);
00062 
00063     sum1 = (sum1 & 0xffff) + (sum1 >> 16);
00064     sum2 = (sum2 & 0xffff) + (sum2 >> 16);
00065   }
00066 
00067   /* Check for odd number of bytes */
00068   if (len8 & 1) {
00069     sum1 += ((uint16_t)*data) << 8;
00070     sum2 += sum1;
00071     sum1 = (sum1 & 0xffff) + (sum1 >> 16);
00072     sum2 = (sum2 & 0xffff) + (sum2 >> 16);
00073   }
00074 
00075   /* Second reduction step to reduce sums to 16 bits */
00076   sum1 = (sum1 & 0xffff) + (sum1 >> 16);
00077   sum2 = (sum2 & 0xffff) + (sum2 >> 16);
00078   return (sum2 << 16) | sum1;
00079 }
00080 
00081 #define HT_F32A_DO1(buf, i) sum1 += ntohs(buf[i]); sum2 += sum1;
00082 #define HT_F32A_DO2(buf,i)  HT_F32A_DO1(buf,i); HT_F32A_DO1(buf,i+1);
00083 #define HT_F32A_DO4(buf,i)  HT_F32A_DO2(buf,i); HT_F32A_DO2(buf,i+2);
00084 #define HT_F32A_DO8(buf,i)  HT_F32A_DO4(buf,i); HT_F32A_DO4(buf,i+4);
00085 #define HT_F32A_DO16(buf,i) HT_F32A_DO8(buf,i); HT_F32A_DO8(buf,i+8);
00086 
00087 uint32_t
00088 fletcher32a(const uint16_t *data, size_t len) {
00089   uint32_t sum1 = 0xffff, sum2 = 0xffff;
00090 
00091   while (len) {
00092     /* 360 is the largest number of sums that can be
00093      * performed without integer overflow
00094      */
00095     unsigned tlen = len > 360 ? 360 : len;
00096     len -= tlen;
00097 
00098     if (tlen >= 16) do {
00099       HT_F32A_DO16(data, 0);
00100       data += 16;
00101       tlen -= 16;
00102     } while (tlen >= 16);
00103 
00104     if (tlen != 0) do {
00105       sum1 += ntohs(*data);
00106       ++data;
00107       sum2 += sum1;
00108     } while (--tlen);
00109 
00110     sum1 = (sum1 & 0xffff) + (sum1 >> 16);
00111     sum2 = (sum2 & 0xffff) + (sum2 >> 16);
00112   }
00113   /* Second reduction step to reduce sums to 16 bits */
00114   sum1 = (sum1 & 0xffff) + (sum1 >> 16);
00115   sum2 = (sum2 & 0xffff) + (sum2 >> 16);
00116   return (sum2 << 16) | sum1;
00117 }
00118 
00119 
00120 /* cf. http://en.wikipedia.org/wiki/Adler-32
00121  */
00122 #define MOD_ADLER 65521
00123 
00124 inline uint32_t
00125 adler32_update_wp(uint32_t adler, const void *data8, size_t len) {
00126   const uint8_t *data = (const uint8_t *)data8;
00127   uint32_t a = adler & 0xffff, b = (adler >> 16) & 0xffff;
00128 
00129   while (len) {
00130     /* see the wikipedia page for why 5550 is used
00131      *  instead of 5552 mentioned in the RFC
00132      */
00133     size_t tlen = len > 5550 ? 5550 : len;
00134     len -= tlen;
00135     do {
00136       a += *data++;
00137       b += a;
00138     } while (--tlen);
00139 
00140     a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
00141     b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
00142   }
00143 
00144   /* It can be shown that a <= 0x1013a here, so a single subtract will do. */
00145   if (a >= MOD_ADLER)
00146     a -= MOD_ADLER;
00147 
00148   /* It can be shown that b can reach 0xfff87 here. */
00149   b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
00150 
00151   if (b >= MOD_ADLER)
00152     b -= MOD_ADLER;
00153 
00154   return (b << 16) | a;
00155 }
00156 
00157 uint32_t
00158 adler32_wp(const void *data, size_t len) {
00159   return adler32_update_wp(1, data, len);
00160 }
00161 
00162 #define HT_A32_DO1(buf,i)  a += buf[i]; b += a
00163 #define HT_A32_DO2(buf,i)  HT_A32_DO1(buf,i); HT_A32_DO1(buf,i+1);
00164 #define HT_A32_DO4(buf,i)  HT_A32_DO2(buf,i); HT_A32_DO2(buf,i+2);
00165 #define HT_A32_DO8(buf,i)  HT_A32_DO4(buf,i); HT_A32_DO4(buf,i+4);
00166 #define HT_A32_DO16(buf,i) HT_A32_DO8(buf,i); HT_A32_DO8(buf,i+8);
00167 
00168 inline uint32_t
00169 adler32_update(uint32_t adler, const void *data8, size_t len) {
00170   const uint8_t *data = (const uint8_t *)data8;
00171   uint32_t a = adler & 0xffff, b = (adler >> 16) & 0xffff;
00172 
00173   while (len) {
00174     size_t tlen = len > 5552 ? 5552 : len;
00175     len -= tlen;
00176 
00177     if (tlen >= 16) do {
00178       HT_A32_DO16(data, 0);
00179       data += 16;
00180       tlen -= 16;
00181     } while (tlen >= 16);
00182 
00183     if (tlen != 0) do {
00184       a += *data++;
00185       b += a;
00186     } while (--tlen > 0);
00187 
00188     a %= MOD_ADLER;
00189     b %= MOD_ADLER;
00190   }
00191   return (b << 16) | a;
00192 }
00193 
00194 uint32_t
00195 adler32(const void *data, size_t len) {
00196   return adler32_update(1, data, len);
00197 }
00198 
00199 uint32_t
00200 crc32(const void *data, size_t len) {
00201   uint32_t crc = ::crc32(0LL, Z_NULL, 0);
00202   return ::crc32(crc, (Bytef *)data, len);
00203 }
00204 
00205 uint32_t
00206 crc32_update(uint32_t crc, const void *data, size_t len) {
00207   return ::crc32(crc, (Bytef *)data, len);
00208 }
00209 
00210 } // namespace Hypertable
00211 
00212 /* vim: et sw=2
00213  */