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