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=®ister_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