Mercurial > ~dholland > hg > ag > index.cgi
diff anagram/agcore/checksum.cpp @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/anagram/agcore/checksum.cpp Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,259 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 1993-1999 Parsifal Software. All Rights Reserved. + * Copyright 2006 David A. Holland. All Rights Reserved. + * See the file COPYING for license and usage terms. + * + * checksum.cpp - self-checksum module + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "port.h" + +#ifdef AG_ON_WINDOWS +#include <windows.h> +#endif + +#include "agstring.h" +#include "assert.h" +#include "checksum.h" +#include "file.h" + +//#define INCLUDE_LOGGING +#include "log.h" + + +/* + * Fletcher's check-sum routines for AnaGram + * + * Freely adapted from routines published in Dr. Dobbs Journal + * May 1992, p. 64 + */ + +#define BLOCK_SIZE 0X4000U + +static AgString basedir; + +static void checkSum(int fh, int offset, u_long *res_sum, u_long *res_len) { + LOGSECTION("checkSum"); + char *buf; + unsigned short k1, k2; + + *res_sum = 0; + *res_len = 0; + + //LOGV(fh); + + if (fh < 0) { + return; + } + lseek(fh, 0, 2); + int length = tell(fh); + *res_len = length; + //LOGV(length); + //buf = ALLOCATE(BLOCK_SIZE + 1, char); + buf = new char[BLOCK_SIZE + 1]; + + k1 = (unsigned short) (length >> 16); + k2 = (unsigned short) length; + + if (offset) { + lseek(fh, offset+512, 0); + length -= offset+512; + //LOGV(length); + } + else { + lseek(fh,0,0); + } + + if (k1 == 0) k1++; + if (k2 == 0) k2++; + + while (length > 0) { + unsigned n; + unsigned ni; + unsigned i; + unsigned short *b; + + n = BLOCK_SIZE; + if ((long) n > length) { + n = (unsigned short) length; + } + n = read(fh, buf, n); + if (n == 0) { + break; + } + ni = (n+1)/2; + i = 0; + b = (unsigned short *) buf; + buf[n] = 0; + while (i< ni) { + k1 += b[i]; + if (k1 < b[i]) { + k1++; + } + k2 += k1; + if (k2 < k1) { + k2++; + } + i++; + } + length -= n; + if (length <= 0 && offset!=0) { + //LOGV(k1) LCV(k2); + length = offset; + offset = 0; + lseek(fh, 0, 0); + } + } + k1 ^= (unsigned short) -1; + k2 ^= (unsigned short) -1; + *res_sum = 65535L*k2 + k1; + + LOGV(*res_sum); + //DEALLOCATE(buf); + delete [] buf; +} + +#ifdef AG_ON_WINDOWS +static int open_binary(summable what) { + char buf[_MAX_PATH]; + HMODULE module; + + switch (what) { + case SUM_AG1: module = GetModuleHandle("ag1"); break; + case SUM_AG: module = 0; break; + case SUM_AGCL: module = 0; break; + } + + GetModuleFileName(module, buf, sizeof(buf)-2); + + if (what != SUM_AG1) { + size_t len = strlen(buf); + if (len >= 6 && !stricmp(buf+len-6, "ag.exe") && what == SUM_AGCL) { + strcpy(buf+len-6, "agcl.exe"); + } + else if (len >= 8 && !stricmp(buf+len-8, "agcl.exe") && what == SUM_AG) { + strcpy(buf+len-8, "ag.exe"); + } + } + + return open_shared_denywrite(buf, O_BINARY|O_RDONLY); +} +#endif + +#ifdef AG_ON_UNIX +static int open_binary(summable what) { + char buf[PATH_MAX]; + const char *name = NULL; + switch (what) { + case SUM_AG1: name = "ag1.so"; break; + case SUM_AG: name = "ag"; break; + case SUM_AGCL: name = "agcl"; break; + } + + snprintf(buf, sizeof(buf), "%s/%s", basedir.pointer(), name); + return open(buf, O_RDONLY); +} +#endif + +static int open_summable(summable what) { + switch (what) { + case SUM_AG1: + case SUM_AG: + case SUM_AGCL: + return open_binary(what); + } + return -1; +} + +static void close_summable(summable what, int fd) { + switch (what) { + case SUM_AG1: + case SUM_AG: + case SUM_AGCL: + close(fd); + break; + } +} + +void observeSum(sumentry *s) { + LOGSECTION("observeSum"); + + int fd = open_summable(s->what); + if (fd >= 0) { + LOGV(fd); + checkSum(fd, s->offset, &s->observed.sum, &s->observed.length); + close_summable(s->what, fd); + } + else { + s->observed.sum = 0; + s->observed.length = 0; + } +} + +void sum_remember_argv0(const char *argv0) { + LOGSECTION("sum_remember_argv0"); + LOGV(argv0); + AgString av0(argv0); + +#ifdef AG_ON_WINDOWS + basedir = av0.lastCut("\\/:").leftX(); + LOGV(basedir); +#endif + +#ifdef AG_ON_UNIX + /* + * Not as simple on Unix - we get whatever the parent process sends + * us, which is typically what the user typed into the shell to + * invoke the program. That is, it might be an absolute path, a + * relative path, or no path at all, and in the latter case we need + * to search $PATH. Blah. + * + * Note that since both argv[0] and $PATH are under the user's + * control, if the user is adversarial we can't count on finding the + * same file that we're actually executing from. Fortunately we + * don't care about that now AG is open source. + */ + + if (argv0[0]=='/') { + /* absolute path */ + basedir = av0.lastCut("\\/:").leftX(); + LOGV(basedir); + } + else if (strrchr(argv0, '/')!=NULL) { + /* relative path - good enough; we don't chdir before summing is done */ + basedir = av0.lastCut("\\/:").leftX(); + LOGV(basedir); + } + else { + /* nothing */ + struct stat sb; + const char *p = getenv("PATH"); + LOGV(p); + if (p) { + AgString path(p); // copy it + for (char *s = strtok(path.pointer(), ":"); s; s = strtok(NULL, ":")) { + char tmp[PATH_MAX]; + snprintf(tmp, sizeof(tmp), "%s/%s", s, argv0); + LOGV(tmp); + if (stat(tmp, &sb)==0) { + basedir = s; // copy it + LOGV(basedir); + return; + } + } + } + + /* oh well - let's make a guess */ + basedir = "/usr/local/lib/anagram"; + LOGV(basedir); + } +#endif +}