1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "mdglobal.h"
4 #include "md5.h"
5 #if defined(CRAY)&& !defined(__crayx1)
6 #include <fortran.h>
7 #endif
8 #include "typesf2c.h"
9
10 /*
11 $Id$
12 */
13
14 #if defined(USE_FCD)
15 extern int string_to_fortchar(_fcd f, int flen, char *buf);
16 #else
17 extern int string_to_fortchar(char *f, int flen, char *buf);
18 #endif
19
20 #if (defined(CRAY) || defined(WIN32))&& !defined(__crayx1) &&!defined(__MINGW32__)
21 #define checksum_simple_ CHECKSUM_SIMPLE
22 #define checksum_init_ CHECKSUM_INIT
23 #define checksum_update_ CHECKSUM_UPDATE
24 #define checksum_final_ CHECKSUM_FINAL
25 #define checksum_char_update_ CHECKSUM_CHAR_UPDATE
26 #define checksum_char_simple_ CHECKSUM_CHAR_SIMPLE
27 #endif
28
29 /* This passes mddriver -x test using munged MDstring in mddriver.c
30 and also produces the same checksum when compressing stdin */
31
32 /* Define this to compile the test main program */
33 /*#define MD5TEST*/
34
35 static MD5_CTX context;
36 #ifdef EXT_INT
37 typedef long integer; /* FORTRAN integer */
38 #else
39 typedef int integer; /* FORTRAN integer */
40 #endif
41
42 /* C interface */
43 /**
44 \ingroup checksum
45 @{
46 Initialize the internal checksum. `checksum_update()` may then
47 be called repeatedly. The result does NOT depend on the number
48 of calls to `checksum_update()`. E.g., the checksum of an array
49 element-by-element is the same as the checksum of all elements
50 (in the same order) at once.
51 */
52
checksum_init(void)53 void checksum_init(void)
54 {
55 MD5Init(&context);
56 }
57
58 /**
59 Update the internal checksum with `len` bytes of data from the
60 location pointed to by `buf`. Fortran may use the MA routines
61 for portable conversion of lengths into bytes.
62 \param len [Input] length of data in bytes
63 \param buf [Input] data to checksum
64 */
65
checksum_update(int len,const void * buf)66 void checksum_update(int len, const void *buf)
67 {
68 MD5Update(&context, buf, (unsigned int) len);
69 }
70
checksum_sum_to_string(const unsigned char sum[16],char csum[33])71 static void checksum_sum_to_string(const unsigned char sum[16], char csum[33])
72 {
73 int i;
74 char *c;
75
76 for (c=csum, i=0; i < 16; i++, c+=2)
77 (void) sprintf (c, "%02x", sum[i]);
78 *c = 0;
79 }
80
81 /**
82 Finish generating the checksum and return the checksum value
83 as a C (null terminated) or Fortran character string.
84 \param csum [Output] The checksum value
85 */
86
checksum_final(char csum[33])87 void checksum_final(char csum[33])
88 {
89 unsigned char sum[16];
90
91 MD5Final(sum, &context);
92 checksum_sum_to_string(sum, csum);
93 }
94
95 /**
96 Convenience routine when checksumming a single piece of data.
97 Same as:
98 ~~~~
99 call checksum_init()
100 call checksum_update(len, buf)
101 call checksum_final(sum)
102 ~~~~
103 \param len [Input] The length of the data in bytes
104 \param buf [Input] The data to checksum
105 \param csum [Output] The checksum value
106 */
107
checksum_simple(int len,const void * buf,char csum[33])108 void checksum_simple(int len, const void *buf, char csum[33])
109 {
110 checksum_init();
111 checksum_update(len, buf);
112 checksum_final(csum);
113 }
114
115 /* Don't need this routine ? */
checksum_string_to_sum(const char csum[33],unsigned char sum[16])116 static void checksum_string_to_sum(const char csum[33], unsigned char sum[16])
117 {
118 int i, j;
119 char buf[3];
120 const char *c;
121
122 buf[2] = 0;
123
124 for (c=csum, i=0; i < 16; i++, c+=2) {
125 buf[0] = c[0]; buf[1] = c[1];
126 if (sscanf(buf, "%x", &j) != 1) {
127 fprintf(stderr,"checksum_sum_to_string: sscanf failed!\n");
128 exit(1);
129 }
130 sum[i] = j;
131 }
132 }
133
134 /* Fortran interface */
135
136 /**
137 \brief Fortran binding for the `checksum_init` function.
138 */
139
checksum_init_(void)140 void FATR checksum_init_(void)
141 {
142 checksum_init();
143 }
144
145 /**
146 \brief Fortran binding for the `checksum_update` function.
147
148 This function accepts all types of data except character data.
149 The reason for the latter is that character strings are handled
150 differently in Fortran than in C. So for those an additional
151 conversion step is required. See `checksum_char_update` for
152 details.
153 \param len [Input] The number of bytes of data
154 \param buf [Input] The data to be checksummed
155 */
checksum_update_(integer * len,const void * buf)156 void FATR checksum_update_(integer *len, const void *buf)
157 {
158 checksum_update((int) *len, buf);
159 }
160
161 /**
162 \brief The Fortran binding for checksum_update for character strings
163
164 Fortran character strings are handle differently than C strings. In
165 Fortran the length of the string is part of the data structure,
166 whereas in C strings are null terminated. Anyway this difference
167 requires a special interface for Fortran.
168 \param buf [Input] The character data to checksum
169 \param len [Input] The number of characters in the string
170 */
171
172 #if defined(USE_FCD)
checksum_char_update_(_fcd f)173 void FATR checksum_char_update_(_fcd f)
174 {
175 checksum_update(_fcdlen(f), _fcdtocp(f));
176 }
177 #else
checksum_char_update_(const char * buf,int len)178 void FATR checksum_char_update_(const char *buf, int len)
179 {
180 checksum_update(len, buf);
181 }
182 #endif
183
184 /**
185 \brief Fortran binding for `checksum_final`
186
187 \param f [Output] The checksum value
188 \param len [Input] The number of characters reserved for `f`
189
190 */
191
192 #if defined(USE_FCD)
checksum_final_(_fcd f)193 void FATR checksum_final_(_fcd f)
194 {
195 int flen = _fcdlen(f);
196 #else
197 void FATR checksum_final_(char *f, int flen)
198 {
199 #endif
200 char tmp[33];
201
202 checksum_final(tmp);
203
204 if (!string_to_fortchar(f, flen, tmp)) {
205 fprintf(stderr,"checksum_final_: sum needs 32 chars have %d\n", flen);
206 exit(1);
207 }
208 }
209
210 /**
211 \brief The Fortran binding for `checksum_simple`
212
213 This function provides the Fortran bindings for `checksum_simple` for all
214 data types except character strings. The latter are handled differently in
215 Fortran compared to C. Hence a special function is needed for that data type.
216 \param len [Input] The data length in bytes
217 \param buf [Input] The data to checksum
218 \param f [Output] The checksum
219 */
220
221 #if defined(USE_FCD)
222 void checksum_simple_(integer *len, const void *buf, _fcd f)
223 {
224 checksum_init();
225 checksum_update((int) *len, buf);
226 checksum_final_(f);
227 }
228 #else
229 void checksum_simple_(integer *len, const void *buf, char *f, int flen)
230 {
231 checksum_init();
232 checksum_update((int) *len, buf);
233 checksum_final_(f, flen);
234 }
235 #endif
236
237 /**
238 \brief The Fortran binding for `checksum_simple` for character strings
239
240 This function provides the Fortran bindings for `checksum_simple` for
241 character strings. Character strings are handled differently in
242 Fortran compared to C. Hence a special function is needed for that data type.
243 \param len [Input] The data length in bytes
244 \param buf [Input] The data to checksum
245 \param f [Output] The checksum
246 */
247
248 #if defined(USE_FCD)
249 void checksum_char_simple_(_fcd b, _fcd f)
250 {
251 checksum_init();
252 checksum_char_update_(b);
253 checksum_final_(f);
254 }
255 #else
256 void checksum_char_simple_(const char *buf, char *sum, int blen, int slen)
257 {
258 checksum_init();
259 checksum_char_update_(buf, blen);
260 checksum_final_(sum, slen);
261 }
262 #endif
263
264 #ifdef MD5TEST
265 int cmain()
266 {
267 char buf[1024], csum[33];
268 int len;
269
270 checksum_init();
271 while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0)
272 checksum_update(len, buf);
273 checksum_final(csum);
274
275 printf("sum = %s\n", csum);
276
277 return 0;
278 }
279
280 /* Normally defined by NWChem */
281
282 #if defined(USE_FCD)
283 static int string_to_fortchar(_fcd f, int flen, char *buf)
284 #else
285 static int string_to_fortchar(char *f, int flen, char *buf)
286 #endif
287 {
288 int len = (int) strlen(buf), i;
289 #if defined(USE_FCD)
290 flen = _fcdlen(f);
291 #endif
292
293 if (len > flen)
294 return 0; /* Won't fit */
295
296 #if defined(USE_FCD)
297 for (i=0; i<len; i++)
298 _fcdtocp(f)[i] = buf[i];
299 for (i=len; i<flen; i++)
300 _fcdtocp(f)[i] = ' ';
301 #else
302 for (i=0; i<len; i++)
303 f[i] = buf[i];
304 for (i=len; i<flen; i++)
305 f[i] = ' ';
306 #endif
307 return 1;
308 }
309 #endif
310
311 /**
312 @}
313 */
314