1 /*
2 
3     File: file_fits.c
4 
5     Copyright (C) 2008 Christophe GRENIER <grenier@cgsecurity.org>
6 
7     This software is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, write the Free Software Foundation, Inc., 51
19     Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
29 #ifdef HAVE_TIME_H
30 #include <time.h>
31 #endif
32 #include <stdio.h>
33 #include "types.h"
34 #include "filegen.h"
35 #ifdef DEBUG_FITS
36 #include "log.h"
37 #endif
38 
39 static void register_header_check_fits(file_stat_t *file_stat);
40 static int header_check_fits(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
41 
42 const file_hint_t file_hint_fits= {
43   .extension="fits",
44   .description="Flexible Image Transport System",
45   .max_filesize=PHOTOREC_MAX_FILE_SIZE,
46   .recover=1,
47   .enable_by_default=1,
48   .register_header_check=&register_header_check_fits
49 };
50 
51 /* FITS is the standard data format used in astronomy, it's also used in quantic physics
52  * Image metadata is store in an ASCII header
53  * Specification can be found at http://fits.gsfc.nasa.gov/ 	*/
54 
fits_get_val(const unsigned char * str)55 static uint64_t fits_get_val(const unsigned char *str)
56 {
57   unsigned int i;
58   uint64_t val=0;
59   for(i=0;i<80 && str[i]!='=';i++);
60   i++;
61   for(;i<80 && str[i]==' ';i++);
62   if(i<80 && str[i]=='-')
63     i++;
64   for(;i<80 && str[i]>='0' && str[i]<='9';i++)
65     val=val*10+str[i]-'0';
66   return val;
67 }
68 
fits_info(const unsigned char * buffer,const unsigned int buffer_size,file_recovery_t * file_recovery,unsigned int * i_pointer)69 static uint64_t fits_info(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery, unsigned int *i_pointer)
70 {
71   uint64_t naxis_size=1;
72   unsigned int i=*i_pointer;
73   /* Header is composed of 80 character fixed-length strings */
74   for(; i+80 < buffer_size &&
75       memcmp(&buffer[i], "END ", 4)!=0;
76       i+=80)
77   {
78     if(memcmp(&buffer[i], "BITPIX",6)==0)
79     {
80       const uint64_t tmp=fits_get_val(&buffer[i]);
81       if(tmp>=8)
82 	naxis_size*=tmp/8;
83     }
84     else if(memcmp(&buffer[i], "NAXIS ",6)==0)
85     {
86       if(fits_get_val(&buffer[i])==0)
87 	naxis_size=0;
88     }
89     else if(memcmp(&buffer[i], "NAXIS",5)==0)
90     {
91       const uint64_t naxis_val=fits_get_val(&buffer[i]);
92       naxis_size*=naxis_val;
93     }
94     else if(memcmp(&buffer[i], "CREA_DAT=", 9)==0)
95     {
96       /*	  CREA_DAT= '2007-08-29T16:22:09' */
97       /*	             0123456789012345678  */
98       const char *date_asc;
99       unsigned int j;
100       for(j=0,date_asc=(const char *)&buffer[i];j<80 && *date_asc!='\'';j++,date_asc++);
101       if(j<60 && *date_asc=='\'')
102       {
103 	date_asc++;
104 	file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(date_asc);
105       }
106     }
107   }
108   *i_pointer=i;
109   return naxis_size;
110 }
111 
data_check_fits(const unsigned char * buffer,const unsigned int buffer_size,file_recovery_t * file_recovery)112 static data_check_t data_check_fits(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
113 {
114   while(file_recovery->calculated_file_size + buffer_size/2  >= file_recovery->file_size &&
115       file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2)
116   {
117     unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
118     if(memcmp(&buffer[i], "XTENSION", 8)!=0)
119       break;
120     {
121       const unsigned int i_org=i;
122       const uint64_t tmp=fits_info(buffer, buffer_size, file_recovery, &i);
123 #ifdef DEBUG_FITS
124       log_info("data_check_fits cfr=%llu fs=%llu i=%u buffer_size=%u\n",
125 	  (long long unsigned)file_recovery->calculated_file_size,
126 	  (long long unsigned)file_recovery->file_size,
127 	  i, buffer_size);
128 #endif
129       if(tmp==0)
130       {
131 	file_recovery->data_check=NULL;
132 	file_recovery->file_check=NULL;
133 	return DC_CONTINUE;
134       }
135       file_recovery->calculated_file_size+=(i-i_org+2880-1)/2880*2880+(tmp+2880-1)/2880*2880;
136     }
137   }
138   if(file_recovery->file_size + buffer_size/2 >= file_recovery->calculated_file_size)
139     return DC_STOP;
140   return DC_CONTINUE;
141 }
142 
header_check_fits(const unsigned char * buffer,const unsigned int buffer_size,const unsigned int safe_header_only,const file_recovery_t * file_recovery,file_recovery_t * file_recovery_new)143 static int header_check_fits(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
144 {
145   unsigned int i=0;
146   uint64_t naxis_size_max=0;
147   reset_file_recovery(file_recovery_new);
148 #ifdef DJGPP
149   file_recovery_new->extension="fts";
150 #else
151   file_recovery_new->extension=file_hint_fits.extension;
152 #endif
153   file_recovery_new->min_filesize=2880;
154   if(file_recovery_new->blocksize < 80)
155     return 1;
156   {
157     const uint64_t tmp=fits_info(buffer, buffer_size, file_recovery_new, &i);
158     if(tmp==0)
159       return 1;
160     if(naxis_size_max < tmp && tmp > 1)
161       naxis_size_max=tmp;
162   }
163   /* File is composed of several 2880-bytes blocks */
164   file_recovery_new->data_check=&data_check_fits;
165   file_recovery_new->file_check=&file_check_size;
166   file_recovery_new->calculated_file_size=(i+2880-1)/2880*2880+(naxis_size_max+2880-1)/2880*2880;
167   return 1;
168 }
169 
register_header_check_fits(file_stat_t * file_stat)170 static void register_header_check_fits(file_stat_t *file_stat)
171 {
172   register_header_check(0, "SIMPLE  =", 9, &header_check_fits, file_stat);
173 }
174