/src/ffmpeg/libavcodec/fits.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * FITS implementation of common functions |
3 | | * Copyright (c) 2017 Paras Chadha |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg 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 GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include <inttypes.h> |
23 | | #include <limits.h> |
24 | | #include <stdio.h> |
25 | | #include <string.h> |
26 | | #include "libavutil/dict.h" |
27 | | #include "libavutil/error.h" |
28 | | #include "libavutil/log.h" |
29 | | #include "fits.h" |
30 | | |
31 | | int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state) |
32 | 66.6k | { |
33 | 66.6k | header->state = state; |
34 | 66.6k | header->naxis_index = 0; |
35 | 66.6k | header->naxis = 0; |
36 | 66.6k | memset(header->naxisn, 0, sizeof(header->naxisn)); |
37 | 66.6k | header->blank_found = 0; |
38 | 66.6k | header->pcount = 0; |
39 | 66.6k | header->gcount = 1; |
40 | 66.6k | header->groups = 0; |
41 | 66.6k | header->rgb = 0; |
42 | 66.6k | header->image_extension = 0; |
43 | 66.6k | header->bscale = 1.0; |
44 | 66.6k | header->bzero = 0; |
45 | 66.6k | header->data_min_found = 0; |
46 | 66.6k | header->data_max_found = 0; |
47 | 66.6k | return 0; |
48 | 66.6k | } |
49 | | |
50 | | static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value) |
51 | 442k | { |
52 | 442k | if (metadata) |
53 | 73.8k | av_dict_set(*metadata, keyword, value, 0); |
54 | 442k | return 0; |
55 | 442k | } |
56 | | |
57 | | /** |
58 | | * Extract keyword and value from a header line (80 bytes) and store them in keyword and value strings respectively |
59 | | * @param ptr8 pointer to the data |
60 | | * @param keyword pointer to the char array in which keyword is to be stored |
61 | | * @param value pointer to the char array in which value is to be stored |
62 | | * @return 0 if calculated successfully otherwise AVERROR_INVALIDDATA |
63 | | */ |
64 | | static int read_keyword_value(const uint8_t *ptr8, char *keyword, char *value) |
65 | 450k | { |
66 | 450k | int i; |
67 | | |
68 | 3.09M | for (i = 0; i < 8 && ptr8[i] != ' '; i++) { |
69 | 2.64M | keyword[i] = ptr8[i]; |
70 | 2.64M | } |
71 | 450k | keyword[i] = '\0'; |
72 | | |
73 | 450k | if (ptr8[8] == '=') { |
74 | 48.6k | i = 10; |
75 | 451k | while (i < 80 && ptr8[i] == ' ') { |
76 | 402k | i++; |
77 | 402k | } |
78 | | |
79 | 48.6k | if (i < 80) { |
80 | 48.3k | *value++ = ptr8[i]; |
81 | 48.3k | i++; |
82 | 48.3k | if (ptr8[i-1] == '\'') { |
83 | 135k | for (; i < 80 && ptr8[i] != '\''; i++) { |
84 | 132k | *value++ = ptr8[i]; |
85 | 132k | } |
86 | 3.08k | *value++ = '\''; |
87 | 45.2k | } else if (ptr8[i-1] == '(') { |
88 | 98.7k | for (; i < 80 && ptr8[i] != ')'; i++) { |
89 | 97.2k | *value++ = ptr8[i]; |
90 | 97.2k | } |
91 | 1.55k | *value++ = ')'; |
92 | 43.7k | } else { |
93 | 1.00M | for (; i < 80 && ptr8[i] != ' ' && ptr8[i] != '/'; i++) { |
94 | 960k | *value++ = ptr8[i]; |
95 | 960k | } |
96 | 43.7k | } |
97 | 48.3k | } |
98 | 48.6k | } |
99 | 450k | *value = '\0'; |
100 | 450k | return 0; |
101 | 450k | } |
102 | | |
103 | | #define CHECK_KEYWORD(key) \ |
104 | 21.3k | if (strcmp(keyword, key)) { \ |
105 | 1.97k | av_log(avcl, AV_LOG_ERROR, "expected %s keyword, found %s = %s\n", key, keyword, value); \ |
106 | 1.97k | return AVERROR_INVALIDDATA; \ |
107 | 1.97k | } |
108 | | |
109 | | #define CHECK_VALUE(key, val) \ |
110 | 17.6k | if (sscanf(value, "%d", &header->val) != 1) { \ |
111 | 490 | av_log(avcl, AV_LOG_ERROR, "invalid value of %s keyword, %s = %s\n", key, keyword, value); \ |
112 | 490 | return AVERROR_INVALIDDATA; \ |
113 | 490 | } |
114 | | |
115 | | int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata) |
116 | 450k | { |
117 | 450k | int dim_no, ret; |
118 | 450k | int64_t t; |
119 | 450k | double d; |
120 | 450k | char keyword[10], value[72], c; |
121 | | |
122 | 450k | read_keyword_value(line, keyword, value); |
123 | 450k | switch (header->state) { |
124 | 1.51k | case STATE_SIMPLE: |
125 | 1.51k | CHECK_KEYWORD("SIMPLE"); |
126 | | |
127 | 1.40k | if (value[0] == 'F') { |
128 | 4 | av_log(avcl, AV_LOG_WARNING, "not a standard FITS file\n"); |
129 | 1.40k | } else if (value[0] != 'T') { |
130 | 9 | av_log(avcl, AV_LOG_ERROR, "invalid value of SIMPLE keyword, SIMPLE = %c\n", value[0]); |
131 | 9 | return AVERROR_INVALIDDATA; |
132 | 9 | } |
133 | | |
134 | 1.39k | header->state = STATE_BITPIX; |
135 | 1.39k | break; |
136 | 341 | case STATE_XTENSION: |
137 | 341 | CHECK_KEYWORD("XTENSION"); |
138 | | |
139 | 298 | if (!strcmp(value, "'IMAGE '")) { |
140 | 11 | header->image_extension = 1; |
141 | 11 | } |
142 | | |
143 | 298 | header->state = STATE_BITPIX; |
144 | 298 | break; |
145 | 11.4k | case STATE_BITPIX: |
146 | 11.4k | CHECK_KEYWORD("BITPIX"); |
147 | 10.0k | CHECK_VALUE("BITPIX", bitpix); |
148 | | |
149 | 9.75k | switch(header->bitpix) { |
150 | 6.06k | case 8: |
151 | 6.70k | case 16: |
152 | 7.73k | case 32: case -32: |
153 | 9.41k | case 64: case -64: break; |
154 | 339 | default: |
155 | 339 | av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \ |
156 | 339 | return AVERROR_INVALIDDATA; |
157 | 9.75k | } |
158 | | |
159 | 9.41k | dict_set_if_not_null(metadata, keyword, value); |
160 | | |
161 | 9.41k | header->state = STATE_NAXIS; |
162 | 9.41k | break; |
163 | 7.96k | case STATE_NAXIS: |
164 | 7.96k | CHECK_KEYWORD("NAXIS"); |
165 | 7.59k | CHECK_VALUE("NAXIS", naxis); |
166 | 7.38k | dict_set_if_not_null(metadata, keyword, value); |
167 | | |
168 | 7.38k | if (header->naxis) { |
169 | 2.50k | header->state = STATE_NAXIS_N; |
170 | 4.88k | } else { |
171 | 4.88k | header->state = STATE_REST; |
172 | 4.88k | } |
173 | 7.38k | break; |
174 | 3.03k | case STATE_NAXIS_N: |
175 | 3.03k | ret = sscanf(keyword, "NAXIS%d", &dim_no); |
176 | 3.03k | if (ret != 1 || dim_no != header->naxis_index + 1) { |
177 | 486 | av_log(avcl, AV_LOG_ERROR, "expected NAXIS%d keyword, found %s = %s\n", header->naxis_index + 1, keyword, value); |
178 | 486 | return AVERROR_INVALIDDATA; |
179 | 486 | } |
180 | | |
181 | 2.54k | if (sscanf(value, "%d", &header->naxisn[header->naxis_index]) != 1) { |
182 | 207 | av_log(avcl, AV_LOG_ERROR, "invalid value of NAXIS%d keyword, %s = %s\n", header->naxis_index + 1, keyword, value); |
183 | 207 | return AVERROR_INVALIDDATA; |
184 | 207 | } |
185 | | |
186 | 2.34k | dict_set_if_not_null(metadata, keyword, value); |
187 | 2.34k | header->naxis_index++; |
188 | 2.34k | if (header->naxis_index == header->naxis) { |
189 | 1.30k | header->state = STATE_REST; |
190 | 1.30k | } |
191 | 2.34k | break; |
192 | 426k | case STATE_REST: |
193 | 426k | if (!strcmp(keyword, "BLANK") && sscanf(value, "%"SCNd64"", &t) == 1) { |
194 | 513 | header->blank = t; |
195 | 513 | header->blank_found = 1; |
196 | 425k | } else if (!strcmp(keyword, "BSCALE") && sscanf(value, "%lf", &d) == 1) { |
197 | 957 | if (d <= 0) |
198 | 199 | return AVERROR_INVALIDDATA; |
199 | 758 | header->bscale = d; |
200 | 424k | } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) { |
201 | 412 | header->bzero = d; |
202 | 424k | } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) { |
203 | 1.07k | header->rgb = 1; |
204 | 423k | } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) { |
205 | 549 | header->data_max_found = 1; |
206 | 549 | header->data_max = d; |
207 | 422k | } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) { |
208 | 341 | header->data_min_found = 1; |
209 | 341 | header->data_min = d; |
210 | 422k | } else if (!strcmp(keyword, "END")) { |
211 | 1.62k | return 1; |
212 | 420k | } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) { |
213 | 945 | header->groups = (c == 'T'); |
214 | 419k | } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) { |
215 | 1.28k | if (t < 0 || t > INT_MAX) |
216 | 529 | return AVERROR_INVALIDDATA; |
217 | 757 | header->gcount = t; |
218 | 418k | } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) { |
219 | 1.37k | if (t < 0 || t > INT_MAX) |
220 | 557 | return AVERROR_INVALIDDATA; |
221 | 820 | header->pcount = t; |
222 | 820 | } |
223 | 423k | dict_set_if_not_null(metadata, keyword, value); |
224 | 423k | break; |
225 | 450k | } |
226 | 444k | return 0; |
227 | 450k | } |