1 /*
2 fitscheck.c
3
4 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 *
6 * Part of: The LDAC Tools
7 *
8 * Author: E.BERTIN (IAP)
9 *
10 * Contents: Functions related to file integrity
11 *
12 * Last modify: 15/08/2003
13 *
14 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "fitscat_defs.h"
26 #include "fitscat.h"
27
28 #define ENCODE_OFFSET 0x30
29 unsigned int exclude[13] = {0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
30 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60};
31
32 /****** encode_checksum *****************************************************
33 PROTO void encode_checksum(unsigned int sum, char *str)
34 PURPOSE Encode a checksum to ASCII
35 INPUT Checksum,
36 Destination string.
37 OUTPUT -.
38 NOTES Straightforward copy of Seaman & Pence 1995
39 (ftp://iraf.noao.edu/misc/checksum/).
40 AUTHOR E. Bertin (IAP)
41 VERSION 08/05/2001
42 ***/
encode_checksum(unsigned int sum,char * str)43 void encode_checksum(unsigned int sum, char *str)
44
45 {
46 int ch[4],
47 i,j,k, byte, check;
48
49 for (i=0; i<4; i++)
50 {
51 /*-- Each byte becomes four */
52 byte = (sum << 8*i) >> 24;
53 ch[0] = (ch[1] = ch[2] = ch[3] = byte/4 + ENCODE_OFFSET) + (byte%4);
54 for (check=1; check;) /* avoid ASCII punctuation */
55 for (check=k=0; k<13; k++)
56 {
57 if (ch[0]==exclude[k] || ch[1]==exclude[k])
58 {
59 ch[0]++;
60 ch[1]--;
61 check++;
62 }
63 if (ch[2]==exclude[k] || ch[3]==exclude[k])
64 {
65 ch[2]++;
66 ch[3]--;
67 check++;
68 }
69 }
70 for (j=0; j<4; j++) /* assign the bytes */
71 str[(4*j+i+1)%16] = ch[j]; /* permute the bytes for FITS */
72 }
73 str[16] = 0;
74
75 return;
76 }
77
78
79 /****** decode_checksum *****************************************************
80 PROTO unsigned int decode_checksum(char *str)
81 PURPOSE Decode an ASCII checksum
82 INPUT Checksum string.
83 OUTPUT Checksum.
84 NOTES Straightforward copy of Seaman & Pence 1995
85 (ftp://iraf.noao.edu/misc/checksum/).
86 AUTHOR E. Bertin (IAP)
87 VERSION 08/05/2001
88 ***/
decode_checksum(char * str)89 unsigned int decode_checksum(char *str)
90
91 {
92 char cbuf[16];
93 unsigned short *sbuf,
94 los,his;
95 unsigned int hi,lo, hicarry,locarry;
96 int i;
97
98 /* Remove the permuted FITS byte alignment and the ASCII 0 offset */
99 for (i=0; i<16; i++)
100 cbuf[i] = str[(i+1)%16] - 0x30;
101 sbuf = (unsigned short *)cbuf;
102 hi = lo = 0;
103 if (bswapflag)
104 for (i=4; i--;)
105 {
106 his = *(sbuf++);
107 los = *(sbuf++);
108 hi += (*((unsigned char *)&his)<<8) + *((unsigned char *)&his+1);
109 lo += (*((unsigned char *)&los)<<8) + *((unsigned char *)&los+1);
110 }
111 else
112 for (i=4; i--;)
113 {
114 hi += *(sbuf++);
115 lo += *(sbuf++);
116 }
117
118 hicarry = hi>>16;
119 locarry = lo>>16;
120 while (hicarry || locarry)
121 {
122 hi = (hi & 0xffff) + locarry;
123 lo = (lo & 0xffff) + hicarry;
124 hicarry = hi >> 16;
125 locarry = lo >> 16;
126 }
127
128 return (hi<<16) + lo;
129 }
130
131
132 /****** compute_blocksum *****************************************************
133 PROTO unsigned int compute_blocksum(char *buf, unsigned int sum)
134 PURPOSE Compute the checksum of a FITS block (2880 bytes)
135 INPUT Pointer to the block,
136 The previous checksum.
137 OUTPUT The new computed checksum.
138 NOTES From Seaman & Pence 1995 (ftp://iraf.noao.edu/misc/checksum/). But
139 contrarily to what is stated by the authors, the original algorithm
140 depends on the endianity of the machine. The routine below adds
141 support for ix386-like processors (non-IEEE).
142 AUTHOR E. Bertin (IAP)
143 VERSION 08/05/2001
144 ***/
compute_blocksum(char * buf,unsigned int sum)145 unsigned int compute_blocksum(char *buf, unsigned int sum)
146 {
147 unsigned short *sbuf,
148 his,los;
149 unsigned int hi,lo, hicarry,locarry;
150 int i;
151
152 sbuf = (unsigned short *)buf;
153 hi = (sum >> 16);
154 lo = (sum << 16) >> 16;
155 if (bswapflag)
156 for (i=FBSIZE/4; i--;)
157 {
158 his = *(sbuf++);
159 los = *(sbuf++);
160 hi += (*((unsigned char *)&his)<<8) + *((unsigned char *)&his+1);
161 lo += (*((unsigned char *)&los)<<8) + *((unsigned char *)&los+1);
162 }
163 else
164 for (i=FBSIZE/4; i--;)
165 {
166 hi += *(sbuf++);
167 lo += *(sbuf++);
168 }
169
170 hicarry = hi>>16; /* fold carry bits in */
171 locarry = lo>>16;
172 while (hicarry || locarry)
173 {
174 hi = (hi & 0xFFFF) + locarry;
175 lo = (lo & 0xFFFF) + hicarry;
176 hicarry = hi >> 16;
177 locarry = lo >> 16;
178 }
179
180 return (hi << 16) + lo;
181 }
182
183
184 /****** compute_bodysum *****************************************************
185 PROTO unsigned int compute_bodysum(tabstruct *tab, unsigned int sum)
186 PURPOSE Compute the checksum of a FITS body
187 INPUT Pointer to the tab,
188 Checksum from a previous iteration.
189 OUTPUT The computed checksum.
190 NOTES -.
191 AUTHOR E. Bertin (IAP)
192 VERSION 15/08/2003
193 ***/
compute_bodysum(tabstruct * tab,unsigned int sum)194 unsigned int compute_bodysum(tabstruct *tab, unsigned int sum)
195 {
196 catstruct *cat;
197 char *buf;
198 KINGSIZE_T size;
199 int n, nblock;
200
201 /* FITS data are generally padded */
202 nblock = (tab->tabsize+FBSIZE-1)/FBSIZE;
203 /* 2 cases: either the data are in memory or still on disk */
204 if (tab->bodybuf)
205 {
206 /*-- In memory: they are probably not padded */
207 buf = (char *)tab->bodybuf;
208 for (n=nblock-1; n--; buf+=FBSIZE)
209 sum = compute_blocksum(buf, sum);
210 if ((size=PADEXTRA(tab->tabsize)))
211 {
212 QCALLOC(buf, char, FBSIZE);
213 size = FBSIZE-size;
214 memcpy(buf, (char *)tab->bodybuf+tab->tabsize-size, size);
215 sum = compute_blocksum(buf, sum);
216 free(buf);
217 }
218 }
219 else
220 {
221 /*-- On disk: they are padded */
222 /*-- We open the file (nothing is done if already open) */
223 if (!(cat=tab->cat))
224 {
225 warning("Cannot access file while computing the checksum in HDU ",
226 tab->extname);
227 return 0;
228 }
229 open_cat(cat, READ_ONLY);
230 QFSEEK(cat->file, tab->bodypos, SEEK_SET, cat->filename);
231 QMALLOC(buf, char, FBSIZE);
232 for (n=nblock; n--;)
233 {
234 QFREAD(buf, FBSIZE, cat->file, cat->filename);
235 /*---- No need to swap bytes */
236 sum = compute_blocksum(buf, sum);
237 }
238 }
239
240 return sum;
241 }
242
243
244 /****** write_checksum *****************************************************
245 PROTO void write_checksum(tabstruct *tab)
246 PURPOSE Compute and write the checksum to a FITS table
247 INPUT Pointer to the tab.
248 OUTPUT -.
249 NOTES -.
250 AUTHOR E. Bertin (IAP)
251 VERSION 04/06/2001
252 ***/
write_checksum(tabstruct * tab)253 void write_checksum(tabstruct *tab)
254
255 {
256 char str[32],
257 *buf;
258 unsigned int sum;
259 int i;
260
261 /* Keep some margin */
262 QREALLOC(tab->headbuf, char, 80*(tab->headnblock*36+3));
263 /* Add or update keywords in the header */
264 fitsadd(tab->headbuf, "CHECKSUM", "ASCII 1's complement checksum");
265 fitswrite(tab->headbuf, "CHECKSUM", "0000000000000000",
266 H_STRING, T_STRING);
267 fitsadd(tab->headbuf, "DATASUM ", "Checksum of data records");
268 fitswrite(tab->headbuf, "DATASUM ", "0", H_STRING, T_STRING);
269 fitsadd(tab->headbuf, "CHECKVER", "Checksum version ID");
270 fitswrite(tab->headbuf, "CHECKVER", "COMPLEMENT", H_STRING, T_STRING);
271 /* Keep only what's necessary */
272 tab->headnblock = ((fitsfind(tab->headbuf, "END ")+36)*80)/FBSIZE;
273 QREALLOC(tab->headbuf, char, tab->headnblock*FBSIZE);
274 /* First: the data */
275 tab->bodysum = sum = compute_bodysum(tab, 0);
276 sprintf(str, "%u", sum);
277 fitswrite(tab->headbuf, "DATASUM ", str, H_STRING, T_STRING);
278
279
280 /* Now the header */
281 buf = tab->headbuf;
282 for (i=tab->headnblock; i--; buf+=FBSIZE)
283 sum = compute_blocksum(buf, sum);
284
285 /* Complement to 1 */
286 encode_checksum(~sum, str);
287 fitswrite(tab->headbuf, "CHECKSUM", str, H_STRING, T_STRING);
288
289 return;
290 }
291
292
293 /****** verify_checksum *****************************************************
294 PROTO int verify_checksum(tabstruct *tab)
295 PURPOSE Compute and check the checksum of a FITS table
296 INPUT Pointer to the tab.
297 OUTPUT RETURN_OK if the checksum is correct, RETURN_ERROR if it is
298 incorrect, or RETURN_FATAL_ERROR if no checksum found.
299 NOTES -.
300 AUTHOR E. Bertin (IAP)
301 VERSION 07/05/2001
302 ***/
verify_checksum(tabstruct * tab)303 int verify_checksum(tabstruct *tab)
304
305 {
306 char *buf;
307 unsigned int sum;
308 int i;
309
310 if (fitsfind(tab->headbuf, "CHECKSUM")==RETURN_ERROR)
311 return RETURN_FATAL_ERROR;
312
313 /* First: the data */
314 sum = compute_bodysum(tab, 0);
315 /* Now the header */
316 buf = tab->headbuf;
317 for (i=tab->headnblock; i--; buf+=FBSIZE)
318 sum = compute_blocksum(buf, sum);
319 /* The result should sum to 0 */
320 sum = ~sum;
321
322 return sum? RETURN_ERROR : RETURN_OK;
323 }
324
325