1 /* $Id: qfits_md5.c,v 1.9 2007/01/10 08:53:45 yjung Exp $
2  *
3  * This file is part of the ESO QFITS Library
4  * Copyright (C) 2001-2004 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 /*
22  * $Author: yjung $
23  * $Date: 2007/01/10 08:53:45 $
24  * $Revision: 1.9 $
25  * $Name: qfits-6_2_0 $
26  */
27 
28 /*-----------------------------------------------------------------------------
29                                    Includes
30  -----------------------------------------------------------------------------*/
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include "qfits_md5.h"
39 
40 #include "md5.h"
41 #include "qfits_std.h"
42 #include "qfits_error.h"
43 
44 /*-----------------------------------------------------------------------------
45                                    Defines
46  -----------------------------------------------------------------------------*/
47 
48 /* Size of an MD5 hash in bytes (32 bytes are 128 bits) */
49 #define MD5HASHSZ    32
50 
51 /*----------------------------------------------------------------------------*/
52 /**
53  * @defgroup    qfits_md5   FITS data block MD5 computation routine
54  *
55  * This module offers MD5 computation over all data areas of a FITS file.
56  *
57 */
58 /*----------------------------------------------------------------------------*/
59 /**@{*/
60 
61 /*-----------------------------------------------------------------------------
62                               Function code
63  -----------------------------------------------------------------------------*/
64 
65 /*----------------------------------------------------------------------------*/
66 /**
67   @brief    Compute the MD5 hash of data zones in a FITS file.
68   @param    filename    Name of the FITS file to examine.
69   @return    1 statically allocated character string, or NULL.
70 
71   This function expects the name of a FITS file.
72   It will compute the MD5 hash on all data blocks in the main data section
73   and possibly extensions (including zero-padding blocks if necessary) and
74   return it as a string suitable for inclusion into a FITS keyword.
75 
76   The returned string is statically allocated inside this function,
77   so do not free it or modify it. This function returns NULL in case
78   of error.
79  */
80 /*----------------------------------------------------------------------------*/
qfits_datamd5(const char * filename)81 const char * qfits_datamd5(const char * filename)
82 {
83     static char         datamd5[MD5HASHSZ+1];
84     struct MD5Context    ctx;
85     unsigned char         digest[16];
86     FILE             *    in;
87     char                 buf[FITS_BLOCK_SIZE];
88     char            *    buf_c;
89     int                    i;
90     int                    in_header;
91     int                    check_fits;
92 
93     /* Check entries */
94     if (filename==NULL) return NULL;
95     /* Open input file */
96     if ((in=fopen(filename, "r"))==NULL) {
97         qfits_error("cannot open file %s", filename);
98         return NULL;
99     }
100     /* Initialize all variables */
101     MD5Init(&ctx);
102     in_header=1;
103     check_fits=0;
104     /* Loop over input file */
105     while (fread(buf, 1, FITS_BLOCK_SIZE, in)==FITS_BLOCK_SIZE) {
106         /* First time in the loop: check the file is FITS */
107         if (check_fits==0) {
108             /* Examine first characters in block */
109             if (buf[0]!='S' ||
110                 buf[1]!='I' ||
111                 buf[2]!='M' ||
112                 buf[3]!='P' ||
113                 buf[4]!='L' ||
114                 buf[5]!='E' ||
115                 buf[6]!=' ' ||
116                 buf[7]!=' ' ||
117                 buf[8]!='=') {
118                 qfits_error("file [%s] is not FITS\n", filename);
119                 fclose(in);
120                 return NULL;
121             } else {
122                 check_fits=1;
123             }
124         }
125         if (in_header) {
126             buf_c = buf;
127             for (i=0; i<FITS_NCARDS; i++) {
128                 if (buf_c[0]=='E' &&
129                     buf_c[1]=='N' &&
130                     buf_c[2]=='D' &&
131                     buf_c[3]==' ') {
132                     in_header=0;
133                     break;
134                 }
135                 buf_c += FITS_LINESZ;
136             }
137         } else {
138             /* If current block is a data block */
139             /* Try to locate an extension header */
140             if (buf[0]=='X' &&
141                 buf[1]=='T' &&
142                 buf[2]=='E' &&
143                 buf[3]=='N' &&
144                 buf[4]=='S' &&
145                 buf[5]=='I' &&
146                 buf[6]=='O' &&
147                 buf[7]=='N' &&
148                 buf[8]=='=') {
149                 in_header=1;
150                 buf_c = buf;
151                 for (i=0; i<FITS_NCARDS; i++) {
152                     /* Try to find an END marker in this block */
153                     if (buf_c[0]=='E' &&
154                         buf_c[1]=='N' &&
155                         buf_c[2]=='D' &&
156                         buf_c[3]==' ') {
157                         /* Found END marker in same block as XTENSION */
158                         in_header=0;
159                         break;
160                     }
161                     buf_c += FITS_LINESZ;
162                 }
163             } else {
164                 MD5Update(&ctx, (unsigned char *)buf, FITS_BLOCK_SIZE);
165             }
166         }
167     }
168     fclose(in);
169     if (check_fits==0) {
170         /* Never went through the read loop: file is not FITS */
171         qfits_error("file [%s] is not FITS", filename);
172         return NULL;
173     }
174     /* Got to the end of file: summarize */
175     MD5Final(digest, &ctx);
176     /* Write digest into a string */
177     sprintf(datamd5,
178     "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
179     digest[ 0],
180     digest[ 1],
181     digest[ 2],
182     digest[ 3],
183     digest[ 4],
184     digest[ 5],
185     digest[ 6],
186     digest[ 7],
187     digest[ 8],
188     digest[ 9],
189     digest[10],
190     digest[11],
191     digest[12],
192     digest[13],
193     digest[14],
194     digest[15]);
195     return datamd5;
196 }
197 
198 /**@}*/
199