view checksum/dosum.c @ 24:a4899cdfc2d6 default tip

Obfuscate the regexps to strip off the IBM compiler's copyright banners. I don't want bots scanning github to think they're real copyright notices because that could cause real problems.
author David A. Holland
date Mon, 13 Jun 2022 00:40:23 -0400
parents 3aa0f5a02342
children
line wrap: on
line source

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 1993 Parsifal Software. All Rights Reserved.
 * Copyright 2006 David A. Holland. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * dosum.c - checksums.
 */

/*
 * Fletcher's check-sum routines for AnaGram
 * 
 * Freely adapted from routines published in Dr. Dobbs Journal
 * May 1992, p. 64
 *
 * Revised as portable C in June 2006.
 */

#include <stdint.h>
#include <string.h>
#include <assert.h>

#include "bits.h"

struct sumstate {
  uint16_t k1, k2;
};

static void sumstate_init(struct sumstate *s, size_t length) {
  s->k1 = (uint16_t) (length >> 16);
  s->k2 = (uint16_t) length;

  if (s->k1 == 0) s->k1++;
  if (s->k2 == 0) s->k2++;
}

static void sumstate_sum(struct sumstate *s, const void *buf, size_t len) {
  const uint8_t *cb;
  unsigned i, n;
  uint16_t x;

  cb = buf;
  n = len/sizeof(uint16_t);
  for (i=0; i<n; i++) {

    // read one octet at a time so the byte order is deterministic
    x = *cb++;
    x += ((uint16_t)*cb++) << 8;

    s->k1 += x;
    if (s->k1 < x) s->k1++;
    s->k2 += s->k1;
    if (s->k2 < s->k1) s->k2++;
  }
}

static uint32_t sumstate_finish(struct sumstate *s) {
  uint32_t sum;

  s->k1 ^= 0xffff;
  s->k2 ^= 0xffff;
  sum = 65535UL*s->k2 + s->k1;

  return sum;
}

uint32_t dosum(const char *buf, size_t len, size_t skipstart, size_t skiplen) {
  struct sumstate s;
  size_t numwords;

  assert(skiplen%2==0);
  assert(skipstart==0 || skipstart+skiplen <= len);
  sumstate_init(&s, len);

  /*
   * It would be nice if we could count on skipstart being aligned.
   * But we can't. Nor is the filesize necessarily even.
   *
   * The followed mangled logic that rounds some things up matches
   * what used to be done in an even uglier way.
   *
   * To wit: if there's a skip area, we start after it and read pairs
   * of octets, including a zero past the end of the file if the
   * remaining data length after the skip area has odd size, so as to
   * get the last byte. (The caller is responsible for making sure
   * there's a zero there.) Then we read the beginning of the file up
   * to the skip area, but round down so as to not read the first byte
   * of the skip area if skipstart is odd. If skipstart is odd then we
   * wedge in that last byte along with a zero.
   *
   * If there isn't a skip area, we read the whole thing in order,
   * including the zero past the end if the size is odd.
   */

  assert(sizeof(uint16_t)==2);
  numwords = (len+1)/2;

  if (skipstart > 0) {
    size_t p0 = skipstart+skiplen;
    size_t l0 = (numwords - p0/2) * 2;
    size_t p1 = 0;
    size_t l1 = (skipstart/2) * 2;

    sumstate_sum(&s, buf+p0, l0);
    sumstate_sum(&s, buf+p1, l1);
    if (skipstart % 2 == 1) {
       char tmp[2];

       tmp[0] = buf[skipstart - 1];
       tmp[1] = 0;
       sumstate_sum(&s, tmp, 2);
    }
  }
  else {
    sumstate_sum(&s, buf, numwords * 2);
  }

  return sumstate_finish(&s);
}