]> git.sesse.net Git - ffmpeg/blob - libavcodec/fits.c
avformat/avio: Add Metacube support
[ffmpeg] / libavcodec / fits.c
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 "avcodec.h"
23 #include "libavutil/dict.h"
24 #include "fits.h"
25
26 int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state)
27 {
28     header->state = state;
29     header->naxis_index = 0;
30     header->blank_found = 0;
31     header->pcount = 0;
32     header->gcount = 1;
33     header->groups = 0;
34     header->rgb = 0;
35     header->image_extension = 0;
36     header->bscale = 1.0;
37     header->bzero = 0;
38     header->data_min_found = 0;
39     header->data_max_found = 0;
40     return 0;
41 }
42
43 static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
44 {
45     if (metadata)
46         av_dict_set(*metadata, keyword, value, 0);
47     return 0;
48 }
49
50 /**
51  * Extract keyword and value from a header line (80 bytes) and store them in keyword and value strings respectively
52  * @param ptr8 pointer to the data
53  * @param keyword pointer to the char array in which keyword is to be stored
54  * @param value pointer to the char array in which value is to be stored
55  * @return 0 if calculated successfully otherwise AVERROR_INVALIDDATA
56  */
57 static int read_keyword_value(const uint8_t *ptr8, char *keyword, char *value)
58 {
59     int i;
60
61     for (i = 0; i < 8 && ptr8[i] != ' '; i++) {
62         keyword[i] = ptr8[i];
63     }
64     keyword[i] = '\0';
65
66     if (ptr8[8] == '=') {
67         i = 10;
68         while (i < 80 && ptr8[i] == ' ') {
69             i++;
70         }
71
72         if (i < 80) {
73             *value++ = ptr8[i];
74             i++;
75             if (ptr8[i-1] == '\'') {
76                 for (; i < 80 && ptr8[i] != '\''; i++) {
77                     *value++ = ptr8[i];
78                 }
79                 *value++ = '\'';
80             } else if (ptr8[i-1] == '(') {
81                 for (; i < 80 && ptr8[i] != ')'; i++) {
82                     *value++ = ptr8[i];
83                 }
84                 *value++ = ')';
85             } else {
86                 for (; i < 80 && ptr8[i] != ' ' && ptr8[i] != '/'; i++) {
87                     *value++ = ptr8[i];
88                 }
89             }
90         }
91     }
92     *value = '\0';
93     return 0;
94 }
95
96 #define CHECK_KEYWORD(key) \
97     if (strcmp(keyword, key)) { \
98         av_log(avcl, AV_LOG_ERROR, "expected %s keyword, found %s = %s\n", key, keyword, value); \
99         return AVERROR_INVALIDDATA; \
100     }
101
102 #define CHECK_VALUE(key, val) \
103     if (sscanf(value, "%d", &header->val) != 1) { \
104         av_log(avcl, AV_LOG_ERROR, "invalid value of %s keyword, %s = %s\n", key, keyword, value); \
105         return AVERROR_INVALIDDATA; \
106     }
107
108 int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata)
109 {
110     int dim_no, ret;
111     int64_t t;
112     double d;
113     char keyword[10], value[72], c;
114
115     read_keyword_value(line, keyword, value);
116     switch (header->state) {
117     case STATE_SIMPLE:
118         CHECK_KEYWORD("SIMPLE");
119
120         if (value[0] == 'F') {
121             av_log(avcl, AV_LOG_WARNING, "not a standard FITS file\n");
122         } else if (value[0] != 'T') {
123             av_log(avcl, AV_LOG_ERROR, "invalid value of SIMPLE keyword, SIMPLE = %c\n", value[0]);
124             return AVERROR_INVALIDDATA;
125         }
126
127         header->state = STATE_BITPIX;
128         break;
129     case STATE_XTENSION:
130         CHECK_KEYWORD("XTENSION");
131
132         if (!strcmp(value, "'IMAGE   '")) {
133             header->image_extension = 1;
134         }
135
136         header->state = STATE_BITPIX;
137         break;
138     case STATE_BITPIX:
139         CHECK_KEYWORD("BITPIX");
140         CHECK_VALUE("BITPIX", bitpix);
141
142         switch(header->bitpix) {
143         case   8:
144         case  16:
145         case  32: case -32:
146         case  64: case -64: break;
147         default:
148             av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \
149             return AVERROR_INVALIDDATA;
150         }
151
152         dict_set_if_not_null(metadata, keyword, value);
153
154         header->state = STATE_NAXIS;
155         break;
156     case STATE_NAXIS:
157         CHECK_KEYWORD("NAXIS");
158         CHECK_VALUE("NAXIS", naxis);
159         dict_set_if_not_null(metadata, keyword, value);
160
161         if (header->naxis) {
162             header->state = STATE_NAXIS_N;
163         } else {
164             header->state = STATE_REST;
165         }
166         break;
167     case STATE_NAXIS_N:
168         ret = sscanf(keyword, "NAXIS%d", &dim_no);
169         if (ret != 1 || dim_no != header->naxis_index + 1) {
170             av_log(avcl, AV_LOG_ERROR, "expected NAXIS%d keyword, found %s = %s\n", header->naxis_index + 1, keyword, value);
171             return AVERROR_INVALIDDATA;
172         }
173
174         if (sscanf(value, "%d", &header->naxisn[header->naxis_index]) != 1) {
175             av_log(avcl, AV_LOG_ERROR, "invalid value of NAXIS%d keyword, %s = %s\n", header->naxis_index + 1, keyword, value);
176             return AVERROR_INVALIDDATA;
177         }
178
179         dict_set_if_not_null(metadata, keyword, value);
180         header->naxis_index++;
181         if (header->naxis_index == header->naxis) {
182             header->state = STATE_REST;
183         }
184         break;
185     case STATE_REST:
186         if (!strcmp(keyword, "BLANK") && sscanf(value, "%"SCNd64"", &t) == 1) {
187             header->blank = t;
188             header->blank_found = 1;
189         } else if (!strcmp(keyword, "BSCALE") && sscanf(value, "%lf", &d) == 1) {
190             if (d <= 0)
191                 return AVERROR_INVALIDDATA;
192             header->bscale = d;
193         } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) {
194             header->bzero = d;
195         } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) {
196             header->rgb = 1;
197         } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) {
198             header->data_max_found = 1;
199             header->data_max = d;
200         } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) {
201             header->data_min_found = 1;
202             header->data_min = d;
203         } else if (!strcmp(keyword, "END")) {
204             return 1;
205         } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) {
206             header->groups = (c == 'T');
207         } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
208             if (t < 0 || t > INT_MAX)
209                 return AVERROR_INVALIDDATA;
210             header->gcount = t;
211         } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
212             if (t < 0 || t > INT_MAX)
213                 return AVERROR_INVALIDDATA;
214             header->pcount = t;
215         }
216         dict_set_if_not_null(metadata, keyword, value);
217         break;
218     }
219     return 0;
220 }