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