FFmpeg
fits.c
Go to the documentation of this file.
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 
32 {
33  header->state = state;
34  header->naxis_index = 0;
35  header->naxis = 0;
36  memset(header->naxisn, 0, sizeof(header->naxisn));
37  header->blank_found = 0;
38  header->pcount = 0;
39  header->gcount = 1;
40  header->groups = 0;
41  header->rgb = 0;
42  header->image_extension = 0;
43  header->bscale = 1.0;
44  header->bzero = 0;
45  header->data_min_found = 0;
46  header->data_max_found = 0;
47  return 0;
48 }
49 
50 static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
51 {
52  if (metadata)
53  av_dict_set(*metadata, keyword, value, 0);
54  return 0;
55 }
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 {
66  int i;
67 
68  for (i = 0; i < 8 && ptr8[i] != ' '; i++) {
69  keyword[i] = ptr8[i];
70  }
71  keyword[i] = '\0';
72 
73  if (ptr8[8] == '=') {
74  i = 10;
75  while (i < 80 && ptr8[i] == ' ') {
76  i++;
77  }
78 
79  if (i < 80) {
80  *value++ = ptr8[i];
81  i++;
82  if (ptr8[i-1] == '\'') {
83  for (; i < 80 && ptr8[i] != '\''; i++) {
84  *value++ = ptr8[i];
85  }
86  *value++ = '\'';
87  } else if (ptr8[i-1] == '(') {
88  for (; i < 80 && ptr8[i] != ')'; i++) {
89  *value++ = ptr8[i];
90  }
91  *value++ = ')';
92  } else {
93  for (; i < 80 && ptr8[i] != ' ' && ptr8[i] != '/'; i++) {
94  *value++ = ptr8[i];
95  }
96  }
97  }
98  }
99  *value = '\0';
100  return 0;
101 }
102 
103 #define CHECK_KEYWORD(key) \
104  if (strcmp(keyword, key)) { \
105  av_log(avcl, AV_LOG_ERROR, "expected %s keyword, found %s = %s\n", key, keyword, value); \
106  return AVERROR_INVALIDDATA; \
107  }
108 
109 #define CHECK_VALUE(key, val) \
110  if (sscanf(value, "%d", &header->val) != 1) { \
111  av_log(avcl, AV_LOG_ERROR, "invalid value of %s keyword, %s = %s\n", key, keyword, value); \
112  return AVERROR_INVALIDDATA; \
113  }
114 
116 {
117  int dim_no, ret;
118  int64_t t;
119  double d;
120  char keyword[10], value[72], c;
121 
122  read_keyword_value(line, keyword, value);
123  switch (header->state) {
124  case STATE_SIMPLE:
125  CHECK_KEYWORD("SIMPLE");
126 
127  if (value[0] == 'F') {
128  av_log(avcl, AV_LOG_WARNING, "not a standard FITS file\n");
129  } else if (value[0] != 'T') {
130  av_log(avcl, AV_LOG_ERROR, "invalid value of SIMPLE keyword, SIMPLE = %c\n", value[0]);
131  return AVERROR_INVALIDDATA;
132  }
133 
134  header->state = STATE_BITPIX;
135  break;
136  case STATE_XTENSION:
137  CHECK_KEYWORD("XTENSION");
138 
139  if (!strcmp(value, "'IMAGE '")) {
140  header->image_extension = 1;
141  }
142 
143  header->state = STATE_BITPIX;
144  break;
145  case STATE_BITPIX:
146  CHECK_KEYWORD("BITPIX");
147  CHECK_VALUE("BITPIX", bitpix);
148 
149  switch(header->bitpix) {
150  case 8:
151  case 16:
152  case 32: case -32:
153  case 64: case -64: break;
154  default:
155  av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \
156  return AVERROR_INVALIDDATA;
157  }
158 
160 
161  header->state = STATE_NAXIS;
162  break;
163  case STATE_NAXIS:
164  CHECK_KEYWORD("NAXIS");
165  CHECK_VALUE("NAXIS", naxis);
167 
168  if (header->naxis) {
169  header->state = STATE_NAXIS_N;
170  } else {
171  header->state = STATE_REST;
172  }
173  break;
174  case STATE_NAXIS_N:
175  ret = sscanf(keyword, "NAXIS%d", &dim_no);
176  if (ret != 1 || dim_no != header->naxis_index + 1) {
177  av_log(avcl, AV_LOG_ERROR, "expected NAXIS%d keyword, found %s = %s\n", header->naxis_index + 1, keyword, value);
178  return AVERROR_INVALIDDATA;
179  }
180 
181  if (sscanf(value, "%d", &header->naxisn[header->naxis_index]) != 1) {
182  av_log(avcl, AV_LOG_ERROR, "invalid value of NAXIS%d keyword, %s = %s\n", header->naxis_index + 1, keyword, value);
183  return AVERROR_INVALIDDATA;
184  }
185 
187  header->naxis_index++;
188  if (header->naxis_index == header->naxis) {
189  header->state = STATE_REST;
190  }
191  break;
192  case STATE_REST:
193  if (!strcmp(keyword, "BLANK") && sscanf(value, "%"SCNd64"", &t) == 1) {
194  header->blank = t;
195  header->blank_found = 1;
196  } else if (!strcmp(keyword, "BSCALE") && sscanf(value, "%lf", &d) == 1) {
197  if (d <= 0)
198  return AVERROR_INVALIDDATA;
199  header->bscale = d;
200  } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) {
201  header->bzero = d;
202  } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) {
203  header->rgb = 1;
204  } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) {
205  header->data_max_found = 1;
206  header->data_max = d;
207  } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) {
208  header->data_min_found = 1;
209  header->data_min = d;
210  } else if (!strcmp(keyword, "END")) {
211  return 1;
212  } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) {
213  header->groups = (c == 'T');
214  } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
215  if (t < 0 || t > INT_MAX)
216  return AVERROR_INVALIDDATA;
217  header->gcount = t;
218  } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
219  if (t < 0 || t > INT_MAX)
220  return AVERROR_INVALIDDATA;
221  header->pcount = t;
222  }
224  break;
225  }
226  return 0;
227 }
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
int64_t
long long int64_t
Definition: coverity.c:34
metadata
Stream codec metadata
Definition: ogg-flac-chained-meta.txt:2
AVDictionary
Definition: dict.c:32
CHECK_VALUE
#define CHECK_VALUE(key, val)
Definition: fits.c:109
STATE_XTENSION
@ STATE_XTENSION
Definition: fits.h:31
fits.h
read_keyword_value
static int read_keyword_value(const uint8_t *ptr8, char *keyword, char *value)
Extract keyword and value from a header line (80 bytes) and store them in keyword and value strings r...
Definition: fits.c:64
state
static struct @512 state
avpriv_fits_header_parse_line
int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata)
Parse a single header line.
Definition: fits.c:115
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
STATE_REST
@ STATE_REST
Definition: fits.h:37
CHECK_KEYWORD
#define CHECK_KEYWORD(key)
Definition: fits.c:103
limits.h
dict_set_if_not_null
static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
Definition: fits.c:50
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
error.h
header
static const uint8_t header[24]
Definition: sdr2.c:68
line
Definition: graph2dot.c:48
avpriv_fits_header_init
int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state)
Initialize a single header line.
Definition: fits.c:31
log.h
STATE_BITPIX
@ STATE_BITPIX
Definition: fits.h:32
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
STATE_SIMPLE
@ STATE_SIMPLE
Definition: fits.h:30
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
ret
ret
Definition: filter_design.txt:187
dict.h
FITSHeaderState
FITSHeaderState
Definition: fits.h:29
FITSHeader
Structure to store the header keywords in FITS file.
Definition: fits.h:43
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
STATE_NAXIS_N
@ STATE_NAXIS_N
Definition: fits.h:34
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
STATE_NAXIS
@ STATE_NAXIS
Definition: fits.h:33