comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:13d2b8934445
1 /*
2 * AnaGram, A System for Syntax Directed Programming
3 * Copyright 1993-1999 Parsifal Software. All Rights Reserved.
4 * Copyright 2006 David A. Holland. All Rights Reserved.
5 * See the file COPYING for license and usage terms.
6 *
7 * checksum.cpp - self-checksum module
8 */
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <limits.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include "port.h"
18
19 #ifdef AG_ON_WINDOWS
20 #include <windows.h>
21 #endif
22
23 #include "agstring.h"
24 #include "assert.h"
25 #include "checksum.h"
26 #include "file.h"
27
28 //#define INCLUDE_LOGGING
29 #include "log.h"
30
31
32 /*
33 * Fletcher's check-sum routines for AnaGram
34 *
35 * Freely adapted from routines published in Dr. Dobbs Journal
36 * May 1992, p. 64
37 */
38
39 #define BLOCK_SIZE 0X4000U
40
41 static AgString basedir;
42
43 static void checkSum(int fh, int offset, u_long *res_sum, u_long *res_len) {
44 LOGSECTION("checkSum");
45 char *buf;
46 unsigned short k1, k2;
47
48 *res_sum = 0;
49 *res_len = 0;
50
51 //LOGV(fh);
52
53 if (fh < 0) {
54 return;
55 }
56 lseek(fh, 0, 2);
57 int length = tell(fh);
58 *res_len = length;
59 //LOGV(length);
60 //buf = ALLOCATE(BLOCK_SIZE + 1, char);
61 buf = new char[BLOCK_SIZE + 1];
62
63 k1 = (unsigned short) (length >> 16);
64 k2 = (unsigned short) length;
65
66 if (offset) {
67 lseek(fh, offset+512, 0);
68 length -= offset+512;
69 //LOGV(length);
70 }
71 else {
72 lseek(fh,0,0);
73 }
74
75 if (k1 == 0) k1++;
76 if (k2 == 0) k2++;
77
78 while (length > 0) {
79 unsigned n;
80 unsigned ni;
81 unsigned i;
82 unsigned short *b;
83
84 n = BLOCK_SIZE;
85 if ((long) n > length) {
86 n = (unsigned short) length;
87 }
88 n = read(fh, buf, n);
89 if (n == 0) {
90 break;
91 }
92 ni = (n+1)/2;
93 i = 0;
94 b = (unsigned short *) buf;
95 buf[n] = 0;
96 while (i< ni) {
97 k1 += b[i];
98 if (k1 < b[i]) {
99 k1++;
100 }
101 k2 += k1;
102 if (k2 < k1) {
103 k2++;
104 }
105 i++;
106 }
107 length -= n;
108 if (length <= 0 && offset!=0) {
109 //LOGV(k1) LCV(k2);
110 length = offset;
111 offset = 0;
112 lseek(fh, 0, 0);
113 }
114 }
115 k1 ^= (unsigned short) -1;
116 k2 ^= (unsigned short) -1;
117 *res_sum = 65535L*k2 + k1;
118
119 LOGV(*res_sum);
120 //DEALLOCATE(buf);
121 delete [] buf;
122 }
123
124 #ifdef AG_ON_WINDOWS
125 static int open_binary(summable what) {
126 char buf[_MAX_PATH];
127 HMODULE module;
128
129 switch (what) {
130 case SUM_AG1: module = GetModuleHandle("ag1"); break;
131 case SUM_AG: module = 0; break;
132 case SUM_AGCL: module = 0; break;
133 }
134
135 GetModuleFileName(module, buf, sizeof(buf)-2);
136
137 if (what != SUM_AG1) {
138 size_t len = strlen(buf);
139 if (len >= 6 && !stricmp(buf+len-6, "ag.exe") && what == SUM_AGCL) {
140 strcpy(buf+len-6, "agcl.exe");
141 }
142 else if (len >= 8 && !stricmp(buf+len-8, "agcl.exe") && what == SUM_AG) {
143 strcpy(buf+len-8, "ag.exe");
144 }
145 }
146
147 return open_shared_denywrite(buf, O_BINARY|O_RDONLY);
148 }
149 #endif
150
151 #ifdef AG_ON_UNIX
152 static int open_binary(summable what) {
153 char buf[PATH_MAX];
154 const char *name = NULL;
155 switch (what) {
156 case SUM_AG1: name = "ag1.so"; break;
157 case SUM_AG: name = "ag"; break;
158 case SUM_AGCL: name = "agcl"; break;
159 }
160
161 snprintf(buf, sizeof(buf), "%s/%s", basedir.pointer(), name);
162 return open(buf, O_RDONLY);
163 }
164 #endif
165
166 static int open_summable(summable what) {
167 switch (what) {
168 case SUM_AG1:
169 case SUM_AG:
170 case SUM_AGCL:
171 return open_binary(what);
172 }
173 return -1;
174 }
175
176 static void close_summable(summable what, int fd) {
177 switch (what) {
178 case SUM_AG1:
179 case SUM_AG:
180 case SUM_AGCL:
181 close(fd);
182 break;
183 }
184 }
185
186 void observeSum(sumentry *s) {
187 LOGSECTION("observeSum");
188
189 int fd = open_summable(s->what);
190 if (fd >= 0) {
191 LOGV(fd);
192 checkSum(fd, s->offset, &s->observed.sum, &s->observed.length);
193 close_summable(s->what, fd);
194 }
195 else {
196 s->observed.sum = 0;
197 s->observed.length = 0;
198 }
199 }
200
201 void sum_remember_argv0(const char *argv0) {
202 LOGSECTION("sum_remember_argv0");
203 LOGV(argv0);
204 AgString av0(argv0);
205
206 #ifdef AG_ON_WINDOWS
207 basedir = av0.lastCut("\\/:").leftX();
208 LOGV(basedir);
209 #endif
210
211 #ifdef AG_ON_UNIX
212 /*
213 * Not as simple on Unix - we get whatever the parent process sends
214 * us, which is typically what the user typed into the shell to
215 * invoke the program. That is, it might be an absolute path, a
216 * relative path, or no path at all, and in the latter case we need
217 * to search $PATH. Blah.
218 *
219 * Note that since both argv[0] and $PATH are under the user's
220 * control, if the user is adversarial we can't count on finding the
221 * same file that we're actually executing from. Fortunately we
222 * don't care about that now AG is open source.
223 */
224
225 if (argv0[0]=='/') {
226 /* absolute path */
227 basedir = av0.lastCut("\\/:").leftX();
228 LOGV(basedir);
229 }
230 else if (strrchr(argv0, '/')!=NULL) {
231 /* relative path - good enough; we don't chdir before summing is done */
232 basedir = av0.lastCut("\\/:").leftX();
233 LOGV(basedir);
234 }
235 else {
236 /* nothing */
237 struct stat sb;
238 const char *p = getenv("PATH");
239 LOGV(p);
240 if (p) {
241 AgString path(p); // copy it
242 for (char *s = strtok(path.pointer(), ":"); s; s = strtok(NULL, ":")) {
243 char tmp[PATH_MAX];
244 snprintf(tmp, sizeof(tmp), "%s/%s", s, argv0);
245 LOGV(tmp);
246 if (stat(tmp, &sb)==0) {
247 basedir = s; // copy it
248 LOGV(basedir);
249 return;
250 }
251 }
252 }
253
254 /* oh well - let's make a guess */
255 basedir = "/usr/local/lib/anagram";
256 LOGV(basedir);
257 }
258 #endif
259 }