/src/ffmpeg/libavcodec/fits.c
Line | Count | Source |
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 | 167k | { |
33 | 167k | header->state = state; |
34 | 167k | header->naxis_index = 0; |
35 | 167k | header->naxis = 0; |
36 | 167k | memset(header->naxisn, 0, sizeof(header->naxisn)); |
37 | 167k | header->blank_found = 0; |
38 | 167k | header->pcount = 0; |
39 | 167k | header->gcount = 1; |
40 | 167k | header->groups = 0; |
41 | 167k | header->rgb = 0; |
42 | 167k | header->image_extension = 0; |
43 | 167k | header->bscale = 1.0; |
44 | 167k | header->bzero = 0; |
45 | 167k | header->data_min_found = 0; |
46 | 167k | header->data_max_found = 0; |
47 | 167k | return 0; |
48 | 167k | } |
49 | | |
50 | | static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value) |
51 | 761k | { |
52 | 761k | if (metadata) |
53 | 196k | av_dict_set(*metadata, keyword, value, 0); |
54 | 761k | return 0; |
55 | 761k | } |
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 | 781k | { |
66 | 781k | int i; |
67 | | |
68 | 5.68M | for (i = 0; i < 8 && ptr8[i] != ' '; i++) { |
69 | 4.90M | keyword[i] = ptr8[i]; |
70 | 4.90M | } |
71 | 781k | keyword[i] = '\0'; |
72 | | |
73 | 781k | if (ptr8[8] == '=') { |
74 | 106k | i = 10; |
75 | 610k | while (i < 80 && ptr8[i] == ' ') { |
76 | 504k | i++; |
77 | 504k | } |
78 | | |
79 | 106k | if (i < 80) { |
80 | 106k | *value++ = ptr8[i]; |
81 | 106k | i++; |
82 | 106k | if (ptr8[i-1] == '\'') { |
83 | 105k | for (; i < 80 && ptr8[i] != '\''; i++) { |
84 | 103k | *value++ = ptr8[i]; |
85 | 103k | } |
86 | 2.55k | *value++ = '\''; |
87 | 103k | } else if (ptr8[i-1] == '(') { |
88 | 91.5k | for (; i < 80 && ptr8[i] != ')'; i++) { |
89 | 90.1k | *value++ = ptr8[i]; |
90 | 90.1k | } |
91 | 1.44k | *value++ = ')'; |
92 | 102k | } else { |
93 | 2.85M | for (; i < 80 && ptr8[i] != ' ' && ptr8[i] != '/'; i++) { |
94 | 2.75M | *value++ = ptr8[i]; |
95 | 2.75M | } |
96 | 102k | } |
97 | 106k | } |
98 | 106k | } |
99 | 781k | *value = '\0'; |
100 | 781k | return 0; |
101 | 781k | } |
102 | | |
103 | | #define CHECK_KEYWORD(key) \ |
104 | 42.5k | if (strcmp(keyword, key)) { \ |
105 | 2.64k | av_log(avcl, AV_LOG_ERROR, "expected %s keyword, found %s = %s\n", key, keyword, value); \ |
106 | 2.64k | return AVERROR_INVALIDDATA; \ |
107 | 2.64k | } |
108 | | |
109 | | #define CHECK_VALUE(key, val) \ |
110 | 37.3k | if (sscanf(value, "%d", &header->val) != 1) { \ |
111 | 534 | av_log(avcl, AV_LOG_ERROR, "invalid value of %s keyword, %s = %s\n", key, keyword, value); \ |
112 | 534 | return AVERROR_INVALIDDATA; \ |
113 | 534 | } |
114 | | |
115 | | int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata) |
116 | 781k | { |
117 | 781k | int dim_no, ret; |
118 | 781k | int64_t t; |
119 | 781k | double d; |
120 | 781k | char keyword[10], value[72], c; |
121 | | |
122 | 781k | read_keyword_value(line, keyword, value); |
123 | 781k | switch (header->state) { |
124 | 1.94k | case STATE_SIMPLE: |
125 | 1.94k | CHECK_KEYWORD("SIMPLE"); |
126 | | |
127 | 1.82k | if (value[0] == 'F') { |
128 | 3 | av_log(avcl, AV_LOG_WARNING, "not a standard FITS file\n"); |
129 | 1.82k | } else if (value[0] != 'T') { |
130 | 18 | av_log(avcl, AV_LOG_ERROR, "invalid value of SIMPLE keyword, SIMPLE = %c\n", value[0]); |
131 | 18 | return AVERROR_INVALIDDATA; |
132 | 18 | } |
133 | | |
134 | 1.81k | header->state = STATE_BITPIX; |
135 | 1.81k | break; |
136 | 887 | case STATE_XTENSION: |
137 | 887 | CHECK_KEYWORD("XTENSION"); |
138 | | |
139 | 775 | if (!strcmp(value, "'IMAGE '")) { |
140 | 29 | header->image_extension = 1; |
141 | 29 | } |
142 | | |
143 | 775 | header->state = STATE_BITPIX; |
144 | 775 | break; |
145 | 22.0k | case STATE_BITPIX: |
146 | 22.0k | CHECK_KEYWORD("BITPIX"); |
147 | 20.2k | CHECK_VALUE("BITPIX", bitpix); |
148 | | |
149 | 19.9k | switch(header->bitpix) { |
150 | 10.3k | case 8: |
151 | 11.9k | case 16: |
152 | 15.0k | case 32: case -32: |
153 | 19.4k | case 64: case -64: break; |
154 | 515 | default: |
155 | 515 | av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \ |
156 | 515 | return AVERROR_INVALIDDATA; |
157 | 19.9k | } |
158 | | |
159 | 19.4k | dict_set_if_not_null(metadata, keyword, value); |
160 | | |
161 | 19.4k | header->state = STATE_NAXIS; |
162 | 19.4k | break; |
163 | 17.6k | case STATE_NAXIS: |
164 | 17.6k | CHECK_KEYWORD("NAXIS"); |
165 | 17.1k | CHECK_VALUE("NAXIS", naxis); |
166 | 16.8k | dict_set_if_not_null(metadata, keyword, value); |
167 | | |
168 | 16.8k | if (header->naxis) { |
169 | 12.9k | header->state = STATE_NAXIS_N; |
170 | 12.9k | } else { |
171 | 3.90k | header->state = STATE_REST; |
172 | 3.90k | } |
173 | 16.8k | break; |
174 | 23.6k | case STATE_NAXIS_N: |
175 | 23.6k | ret = sscanf(keyword, "NAXIS%d", &dim_no); |
176 | 23.6k | if (ret != 1 || dim_no != header->naxis_index + 1) { |
177 | 669 | av_log(avcl, AV_LOG_ERROR, "expected NAXIS%d keyword, found %s = %s\n", header->naxis_index + 1, keyword, value); |
178 | 669 | return AVERROR_INVALIDDATA; |
179 | 669 | } |
180 | | |
181 | 22.9k | if (sscanf(value, "%d", &header->naxisn[header->naxis_index]) != 1) { |
182 | 225 | av_log(avcl, AV_LOG_ERROR, "invalid value of NAXIS%d keyword, %s = %s\n", header->naxis_index + 1, keyword, value); |
183 | 225 | return AVERROR_INVALIDDATA; |
184 | 225 | } |
185 | | |
186 | 22.7k | dict_set_if_not_null(metadata, keyword, value); |
187 | 22.7k | header->naxis_index++; |
188 | 22.7k | if (header->naxis_index == header->naxis) { |
189 | 11.5k | header->state = STATE_REST; |
190 | 11.5k | } |
191 | 22.7k | break; |
192 | 715k | case STATE_REST: |
193 | 715k | if (!strcmp(keyword, "BLANK") && sscanf(value, "%"SCNd64"", &t) == 1) { |
194 | 2.92k | header->blank = t; |
195 | 2.92k | header->blank_found = 1; |
196 | 712k | } else if (!strcmp(keyword, "BSCALE") && sscanf(value, "%lf", &d) == 1) { |
197 | 1.00k | if (d <= 0) |
198 | 232 | return AVERROR_INVALIDDATA; |
199 | 771 | header->bscale = d; |
200 | 711k | } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) { |
201 | 374 | header->bzero = d; |
202 | 710k | } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) { |
203 | 624 | header->rgb = 1; |
204 | 710k | } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) { |
205 | 775 | header->data_max_found = 1; |
206 | 775 | header->data_max = d; |
207 | 709k | } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) { |
208 | 883 | header->data_min_found = 1; |
209 | 883 | header->data_min = d; |
210 | 708k | } else if (!strcmp(keyword, "END")) { |
211 | 11.7k | return 1; |
212 | 696k | } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) { |
213 | 871 | header->groups = (c == 'T'); |
214 | 695k | } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) { |
215 | 1.61k | if (t < 0 || t > INT_MAX) |
216 | 575 | return AVERROR_INVALIDDATA; |
217 | 1.04k | header->gcount = t; |
218 | 694k | } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) { |
219 | 1.65k | if (t < 0 || t > INT_MAX) |
220 | 543 | return AVERROR_INVALIDDATA; |
221 | 1.10k | header->pcount = t; |
222 | 1.10k | } |
223 | 702k | dict_set_if_not_null(metadata, keyword, value); |
224 | 702k | break; |
225 | 781k | } |
226 | 763k | return 0; |
227 | 781k | } |