@@ -210,142 +210,159 @@ FitsInput::close(void)
210210bool
211211FitsInput::read_fits_header (void )
212212{
213- std::string fits_header (HEADER_SIZE , 0 );
214-
215- // we read whole header at once
216- if (fread (&fits_header[0 ], 1 , HEADER_SIZE , m_fd) != HEADER_SIZE ) {
217- if (feof (m_fd))
218- errorfmt (" Hit end of file unexpectedly (offset={})" , ftell (m_fd));
219- else
220- errorfmt (" read error" );
221- return false ; // Read failed
222- }
223-
224- bool found_end = false ;
225- for (int i = 0 ; i < CARDS_PER_HEADER ; ++i) {
226- std::string card (CARD_SIZE , 0 );
227- // reading card number i
228- memcpy (&card[0 ], &fits_header[i * CARD_SIZE ], CARD_SIZE );
229-
230- std::string keyname, value;
231- fits_pvt::unpack_card (card, keyname, value);
232-
233- // END means that this is end of the FITS header
234- // we can now add to the ImageSpec COMMENT, HISTORY and HIERARCH keys
235- if (keyname == " END" ) {
236- // removing white spaces that we use to separate lines of comments
237- // from the end ot the string
238- m_comment = m_comment.substr (0 , m_comment.size () - m_sep.size ());
239- m_history = m_history.substr (0 , m_history.size () - m_sep.size ());
240- m_hierarch = m_hierarch.substr (0 , m_hierarch.size () - m_sep.size ());
241- add_to_spec (" Comment" , m_comment);
242- add_to_spec (" History" , m_history);
243- add_to_spec (" Hierarch" , m_hierarch);
244- found_end = true ;
245- break ;
213+ // Arbitrary limit to the number of header blocks in a file before we
214+ // conclude that it's a corrupted file. There are FITS files that *could*
215+ // have more headers, but there is no real limit, so we just pick one.
216+ // Somebody will let us know if they ever encounter a real world file that
217+ // intentionally exceeds this.
218+ constexpr int max_blocks = 10000 ;
219+
220+ for (int h = 0 ; h < max_blocks; ++h) {
221+ std::string fits_header (HEADER_SIZE , 0 );
222+
223+ // we read whole header at once
224+ if (fread (&fits_header[0 ], 1 , HEADER_SIZE , m_fd) != HEADER_SIZE ) {
225+ if (feof (m_fd))
226+ errorfmt (" Hit end of file unexpectedly (offset={})" ,
227+ ftell (m_fd));
228+ else
229+ errorfmt (" read error" );
230+ return false ; // Read failed
246231 }
247232
248- if (keyname == " SIMPLE" || keyname == " XTENSION" )
249- continue ;
250-
251- // setting up some important fields
252- // m_bitpix - format of the data (eg. bpp)
253- // m_naxes - number of axes
254- // width, height and depth of the image
255- if (keyname == " BITPIX" ) {
256- m_bitpix = Strutil::stoi (&card[10 ]);
257- continue ;
258- }
259- if (keyname == " NAXIS" ) {
260- m_naxes = Strutil::stoi (&card[10 ]);
261- m_naxis.resize (m_naxes);
262- continue ;
263- }
264- if (Strutil::starts_with (keyname, " NAXIS" )) {
265- int i = Strutil::stoi (keyname.substr (5 ));
266- if (i > 0 && i <= m_naxes)
267- m_naxis[i - 1 ] = Strutil::stoi (&card[10 ]);
268- continue ;
269- }
270- if (keyname == " ORIENTAT" ) {
271- add_to_spec (" Orientation" , value);
272- continue ;
233+ bool found_end = false ;
234+ for (int i = 0 ; i < CARDS_PER_HEADER ; ++i) {
235+ std::string card (CARD_SIZE , 0 );
236+ // reading card number i
237+ memcpy (&card[0 ], &fits_header[i * CARD_SIZE ], CARD_SIZE );
238+
239+ std::string keyname, value;
240+ fits_pvt::unpack_card (card, keyname, value);
241+
242+ // END means that this is end of the FITS header
243+ // we can now add to the ImageSpec COMMENT, HISTORY and HIERARCH keys
244+ if (keyname == " END" ) {
245+ // removing white spaces that we use to separate lines of comments
246+ // from the end ot the string
247+ m_comment = m_comment.substr (0 ,
248+ m_comment.size () - m_sep.size ());
249+ m_history = m_history.substr (0 ,
250+ m_history.size () - m_sep.size ());
251+ m_hierarch = m_hierarch.substr (0 , m_hierarch.size ()
252+ - m_sep.size ());
253+ add_to_spec (" Comment" , m_comment);
254+ add_to_spec (" History" , m_history);
255+ add_to_spec (" Hierarch" , m_hierarch);
256+ found_end = true ;
257+ break ;
258+ }
259+
260+ if (keyname == " SIMPLE" || keyname == " XTENSION" )
261+ continue ;
262+
263+ // setting up some important fields
264+ // m_bitpix - format of the data (eg. bpp)
265+ // m_naxes - number of axes
266+ // width, height and depth of the image
267+ if (keyname == " BITPIX" ) {
268+ m_bitpix = Strutil::stoi (&card[10 ]);
269+ continue ;
270+ }
271+ if (keyname == " NAXIS" ) {
272+ m_naxes = Strutil::stoi (&card[10 ]);
273+ m_naxis.resize (m_naxes);
274+ continue ;
275+ }
276+ if (Strutil::starts_with (keyname, " NAXIS" )) {
277+ int i = Strutil::stoi (keyname.substr (5 ));
278+ if (i > 0 && i <= m_naxes)
279+ m_naxis[i - 1 ] = Strutil::stoi (&card[10 ]);
280+ continue ;
281+ }
282+ if (keyname == " ORIENTAT" ) {
283+ add_to_spec (" Orientation" , value);
284+ continue ;
285+ }
286+ if (keyname == " DATE" ) {
287+ add_to_spec (" DateTime" , convert_date (value));
288+ continue ;
289+ }
290+ if (keyname == " COMMENT" ) {
291+ m_comment += (value + m_sep);
292+ continue ;
293+ }
294+ if (keyname == " HISTORY" ) {
295+ m_history += (value + m_sep);
296+ continue ;
297+ }
298+ if (keyname == " HIERARCH" ) {
299+ m_hierarch += (value + m_sep);
300+ continue ;
301+ }
302+
303+ Strutil::to_lower (keyname); // make lower case
304+ if (keyname.size () >= 1 )
305+ keyname[0 ] = toupper (keyname[0 ]);
306+ add_to_spec (keyname, value);
273307 }
274- if (keyname == " DATE" ) {
275- add_to_spec (" DateTime" , convert_date (value));
276- continue ;
277- }
278- if (keyname == " COMMENT" ) {
279- m_comment += (value + m_sep);
280- continue ;
308+
309+ // Fix up dimensions
310+ while (m_naxes > 1 && m_naxis[m_naxes - 1 ] == 1 ) {
311+ --m_naxes;
281312 }
282- if (keyname == " HISTORY " ) {
283- m_history += (value + m_sep );
284- continue ;
313+ if (m_naxes < 0 || m_naxes > 4 ) {
314+ errorfmt ( " Number of data axes {} not supported " , m_naxes );
315+ return false ;
285316 }
286- if (keyname == " HIERARCH" ) {
287- m_hierarch += (value + m_sep);
288- continue ;
317+ m_spec.nchannels = 1 ;
318+ m_spec.depth = 1 ;
319+ if (m_naxes == 0 || m_naxis[0 ] == 0 ) {
320+ m_spec.width = m_spec.height = 0 ;
321+ } else if (m_naxes == 1 ) {
322+ m_spec.width = m_naxis[0 ];
323+ m_spec.height = 1 ;
324+ } else if (m_naxes == 2 ) {
325+ m_spec.width = m_naxis[0 ];
326+ m_spec.height = m_naxis[1 ];
327+ } else if (m_naxes == 3 && m_naxis[0 ] <= 4 ) {
328+ // 3D, small number of most-rapidly changing dimension: color image?
329+ m_spec.nchannels = m_naxis[0 ];
330+ m_spec.width = m_naxis[1 ];
331+ m_spec.height = m_naxis[2 ];
332+ } else if (m_naxes == 3 ) {
333+ // 3D, large number of most-rapidly changing dimension: volume?
334+ m_spec.width = m_naxis[0 ];
335+ m_spec.height = m_naxis[1 ];
336+ m_spec.depth = m_naxis[2 ];
337+ } else if (m_naxes == 4 ) {
338+ // 4D... volume + color?
339+ m_spec.nchannels = m_naxis[0 ];
340+ m_spec.width = m_naxis[1 ];
341+ m_spec.height = m_naxis[2 ];
342+ m_spec.depth = m_naxis[3 ];
343+ } else {
344+ errorfmt (" Don't know now to read {}-channel FITS image" , m_naxes);
345+ return false ;
289346 }
347+ m_spec.full_width = m_spec.width ;
348+ m_spec.full_height = m_spec.height ;
349+ m_spec.full_depth = m_spec.depth ;
290350
291- Strutil::to_lower (keyname); // make lower case
292- if (keyname.size () >= 1 )
293- keyname[0 ] = toupper (keyname[0 ]);
294- add_to_spec (keyname, value);
295- }
296-
297- // Fix up dimensions
298- while (m_naxes > 1 && m_naxis[m_naxes - 1 ] == 1 ) {
299- --m_naxes;
300- }
301- if (m_naxes < 0 || m_naxes > 4 ) {
302- errorfmt (" Number of data axes {} not supported" , m_naxes);
303- return false ;
304- }
305- m_spec.nchannels = 1 ;
306- m_spec.depth = 1 ;
307- if (m_naxes == 0 || m_naxis[0 ] == 0 ) {
308- m_spec.width = m_spec.height = 0 ;
309- } else if (m_naxes == 1 ) {
310- m_spec.width = m_naxis[0 ];
311- m_spec.height = 1 ;
312- } else if (m_naxes == 2 ) {
313- m_spec.width = m_naxis[0 ];
314- m_spec.height = m_naxis[1 ];
315- } else if (m_naxes == 3 && m_naxis[0 ] <= 4 ) {
316- // 3D, small number of most-rapidly changing dimension: color image?
317- m_spec.nchannels = m_naxis[0 ];
318- m_spec.width = m_naxis[1 ];
319- m_spec.height = m_naxis[2 ];
320- } else if (m_naxes == 3 ) {
321- // 3D, large number of most-rapidly changing dimension: volume?
322- m_spec.width = m_naxis[0 ];
323- m_spec.height = m_naxis[1 ];
324- m_spec.depth = m_naxis[2 ];
325- } else if (m_naxes == 4 ) {
326- // 4D... volume + color?
327- m_spec.nchannels = m_naxis[0 ];
328- m_spec.width = m_naxis[1 ];
329- m_spec.height = m_naxis[2 ];
330- m_spec.depth = m_naxis[3 ];
331- } else {
332- errorfmt (" Don't know now to read {}-channel FITS image" , m_naxes);
333- return false ;
334- }
335- m_spec.full_width = m_spec.width ;
336- m_spec.full_height = m_spec.height ;
337- m_spec.full_depth = m_spec.depth ;
351+ m_spec.attribute (" oiio:subimages" , (int )m_subimages.size ());
338352
339- m_spec.attribute (" oiio:subimages" , (int )m_subimages.size ());
353+ // if (m_spec.width < 1 || m_spec.height < 1 || m_spec.depth < 1 ||
354+ // m_spec.nchannels < 1) {
355+ // errorfmt("Don't know now to read empty (0 pixel) FITS image");
356+ // return false;
357+ // }
340358
341- // if (m_spec.width < 1 || m_spec.height < 1 || m_spec.depth < 1 ||
342- // m_spec.nchannels < 1) {
343- // errorfmt("Don't know now to read empty (0 pixel) FITS image");
344- // return false;
345- // }
359+ // if we didn't found END keyword in current header, we read next one
360+ if (found_end)
361+ return true ;
362+ }
346363
347- // if we didn't found END keyword in current header, we read next one
348- return found_end ? true : read_fits_header ();
364+ errorfmt ( " No END keyword found after reading {} header blocks " , max_blocks);
365+ return false ; // Never found the end
349366}
350367
351368
0 commit comments