summaryrefslogtreecommitdiff
path: root/rollsum.c
diff options
context:
space:
mode:
Diffstat (limited to 'rollsum.c')
-rw-r--r--rollsum.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/rollsum.c b/rollsum.c
new file mode 100644
index 0000000..fce3f82
--- /dev/null
+++ b/rollsum.c
@@ -0,0 +1,35 @@
+/* rollsum.c -- compute the rsync rolling checksum of a data stream
+ */
+
+/* @(#) $Id$ */
+
+#include "rollsum.h"
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+#define OF16(off) {s1 += 16*off; s2 += 136*off;}
+
+void RollsumUpdate(Rollsum *sum,const unsigned char *buf,unsigned int len) {
+ /* ANSI C says no overflow for unsigned.
+ zlib's adler 32 goes to extra effort to avoid overflow*/
+ unsigned long s1 = sum->s1;
+ unsigned long s2 = sum->s2;
+
+ sum->count+=len; /* increment sum count */
+ while (len >= 16) {
+ DO16(buf);
+ OF16(ROLLSUM_CHAR_OFFSET);
+ buf += 16;
+ len -= 16;
+ }
+ while (len != 0) {
+ s1 += (*buf++ + ROLLSUM_CHAR_OFFSET);
+ s2 += s1;
+ len--;
+ }
+ sum->s1=s1;
+ sum->s2=s2;
+}