File Coverage

blib/lib/Astro/FITS/CFITSIO/Simple.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Astro::FITS::CFITSIO::Simple;
2              
3 1     1   38305 use 5.008002;
  1         5  
  1         46  
4 1     1   6 use strict;
  1         2  
  1         243  
5 1     1   6 use warnings;
  1         2  
  1         71  
6              
7             require Exporter;
8              
9 1     1   1002 use Params::Validate qw/ :all /;
  0            
  0            
10              
11             use Carp;
12              
13             use PDL;
14              
15             use Astro::FITS::CFITSIO qw/ :constants /;
16             use Astro::FITS::CFITSIO::CheckStatus;
17             use Astro::FITS::CFITSIO::Simple::Table qw/ :all /;
18             use Astro::FITS::CFITSIO::Simple::Image qw/ :all /;
19              
20              
21             our @ISA = qw(Exporter);
22              
23             # Items to export into callers namespace by default. Note: do not export
24             # names by default without a very good reason. Use EXPORT_OK instead.
25             # Do not simply export all your public functions/methods/constants.
26              
27             # This allows declaration use Astro::FITS::CFITSIO::Table ':all';
28             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
29             # will save memory.
30             our %EXPORT_TAGS = ( 'all' => [ qw(
31             rdfits
32             ) ] );
33              
34             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
35              
36             our @EXPORT = qw(
37            
38             );
39              
40             our $VERSION = '0.18';
41              
42             # cheap and dirty clean up object so that we can maintain
43             # return contexts in rdfits and its delegates by having
44             # cleanup done during object destruction
45             {
46             package Astro::FITS::CFITSIO::Simple::Cleanup;
47              
48             sub new { my $class = shift; bless {@_}, $class };
49             sub set { $_[0]->{$_[1]} = $_[2] };
50             sub DESTROY{ my $s = shift;
51             tie my $status, 'Astro::FITS::CFITSIO::CheckStatus';
52             $s->{fptr}->perlyunpacking($s->{packing})
53             if defined $s->{packing};
54             $s->{fptr}->movabs_hdu( $s->{hdunum}, undef, $status)
55             if defined $s->{hdunum} }
56             }
57              
58              
59              
60             # HDU types we recognize
61             our %HDUType = (
62             img => IMAGE_HDU,
63             image => IMAGE_HDU,
64             binary => BINARY_TBL,
65             bintbl => BINARY_TBL,
66             ascii => ASCII_TBL,
67             any => ANY_HDU,
68             table => undef, # the CFITSIO flags aren't really bits
69             );
70              
71             sub validHDUTYPE { exists $HDUType{lc $_[0]} }
72             sub validHDUNUM { $_[0] =~ /^\d+$/ && $_[0] > 0 }
73              
74              
75              
76             # these are the Params::Validate specifications for rdfits
77             # they are specified separately here, so that parameters
78             # for _rdfitsTable and _rdfitsImage can be split out
79             # from the main option hash
80              
81             our %rdfits_spec =
82             (
83             extname => { type => SCALAR, optional => 1 },
84             extver => { type => SCALAR,
85             depends => 'extname',
86             default => 0 },
87             hdunum => { type => SCALAR,
88             callbacks => { 'illegal HDUNUM' =>
89             \&validHDUNUM,
90             },
91             optional => 1 },
92             hdutype => { type => SCALAR,
93             callbacks => { 'illegal HDU type' =>
94             \&validHDUTYPE,
95             },
96             default => 'any',
97             optional => 1 },
98             resethdu => { type => SCALAR, default => 0 },
99             );
100              
101             sub rdfits
102             {
103              
104             # strip off the options hash
105             my $opts = 'HASH' eq ref $_[-1] ? pop : {};
106              
107             # first arg is fitsfilePtr or filename
108             my $input = shift;
109              
110             croak( "input must be a fitsfilePtr or a file name\n" )
111             unless defined $input &&
112             ( UNIVERSAL::isa( $input, 'fitsfilePtr' ) || ! ref $input );
113              
114              
115             # rdfits is a dispatch routine; we need to filter out the options
116             # for the delegates (and vice versa). final argument validation
117             # is done by the the delegates
118              
119             # shallow copy, then delete non-rdfits options.
120             my %rdfits_opts = %{$opts};
121             delete @rdfits_opts{ grep { !exists $rdfits_spec{ lc($_) } }
122             keys %rdfits_opts };
123              
124             # shallow copy, then delete rdfits options
125             my %delegate_opts = %{$opts};
126             delete @delegate_opts{ keys %rdfits_opts };
127              
128             # if there are additional arguments, guess that we're being
129             # asked for some columns, and set the requested HDUTYPE to table
130             $rdfits_opts{hdutype} = 'table' if @_;
131              
132             # validate arguments
133             my %opt =
134             validate_with( params => [ \%rdfits_opts ],
135             normalize_keys => sub{ lc $_[0] },
136             spec => \%rdfits_spec );
137              
138              
139              
140             # CFITSIO file pointer
141             my $fptr;
142              
143             tie my $status, 'Astro::FITS::CFITSIO::CheckStatus';
144              
145             my $cleanup;
146              
147             # get CFITSIO file pointer
148             if (UNIVERSAL::isa( $input, 'fitsfilePtr'))
149             {
150              
151             $fptr = $input;
152              
153             $cleanup = new Astro::FITS::CFITSIO::Simple::Cleanup
154             ( fptr => $fptr, packing => $fptr->perlyunpacking );
155              
156             if ( $opt{resethdu} )
157             {
158             $fptr->get_hdu_num( my $hdunum );
159             $cleanup->set( hdunum => $hdunum );
160             }
161              
162             }
163             else
164             {
165             $fptr = Astro::FITS::CFITSIO::open_file($input, READONLY,
166             $status = "could not open FITS file '$input'");
167             }
168              
169             # we're not unpacking;
170             $fptr->perlyunpacking(0);
171              
172             # read in all of the extensions
173             if ( $opt{slurp} )
174             {
175             croak( "slurp not yet implemented!\n" );
176             }
177              
178             # read in just one
179             else
180             {
181             my $hdutype;
182              
183             # HDU specified by name
184             if ( exists $opt{extname} )
185             {
186             $fptr->movnam_hdu(ANY_HDU, $opt{extname}, $opt{extver},
187             $status = "could not move to HDU '$opt{extname}:$opt{extver}'");
188              
189             $fptr->get_hdu_type( $hdutype, $status );
190              
191             croak( "requested extension does not match requested HDU type\n" )
192             unless match_hdutype( $opt{hdutype}, $hdutype );
193             }
194              
195             # HDU specified by number?
196             elsif ( exists $opt{hdunum} )
197             {
198             $fptr->movabs_hdu( $opt{hdunum}, $hdutype, $status );
199              
200             croak( "requested extension does not match requested HDU type\n" )
201             unless match_hdutype( $opt{hdutype}, $hdutype );
202             }
203              
204             # first recognizeable one
205             else
206             {
207             # lazy; let CheckStatus do the work.
208             eval {
209             until ( $status )
210             {
211             $fptr->get_hdu_type($hdutype, $status);
212              
213             # check that we're in an actual image, i.e. NAXIS != 0
214             if ( IMAGE_HDU == $hdutype )
215             {
216             $fptr->get_img_dim( my $naxis, $status );
217             next unless $naxis;
218             }
219             last if match_hdutype( $opt{hdutype}, $hdutype );
220              
221             }
222             continue
223             {
224             $fptr->movrel_hdu( 1, $hdutype, $status );
225             }
226             };
227              
228             # ran off end of file
229             croak( "unable to find a matching HDU to read\n" )
230             if BAD_HDU_NUM == $status;
231              
232             # all other errors
233             croak $@ if $@;
234             }
235              
236             # update args. $cleanup must be passed so that it will be destroyed
237             # after the delegate routine has finished.
238             unshift @_, $fptr, $cleanup;
239              
240             # add the options for the delegate
241             push @_, \%delegate_opts;
242              
243             # dispatch. we use the dispatch goto here to keep croak's etc. at the
244             # correct level and to maintain the calling context.
245             BINARY_TBL == $hdutype || ASCII_TBL == $hdutype
246             and goto &_rdfitsTable;
247              
248             IMAGE_HDU == $hdutype
249             and goto &_rdfitsImage;
250              
251             croak( "internal error. bizarre hdutype = $hdutype\n" );
252             }
253              
254             croak( "internal error; can't get here from there\n" );
255              
256             }
257              
258             # a thin front end for reading in a table
259              
260             sub rdfitstbl
261             {
262             # make shallow copy of passed options hash (or create one)
263             my %opt = 'HASH' eq ref $_[-1] ? %{pop @_} : ();
264              
265             # force the HDU to match a table
266             $opt{hdutype} = 'table';
267              
268             # read only one HDU
269             delete $opt{slurp};
270              
271             # make sure only the input file is in there.
272             croak( "too many arguments to rdfitstbl\n" )
273             if @_ > 1;
274              
275             # attach our new options hash
276             push @_, \%opt;
277              
278             # do the whole shebang; pretend we were never here.
279             goto &rdfits;
280             }
281              
282             # a thin front end for reading in an image
283              
284             sub rdfitsimg
285             {
286             # make shallow copy of passed options hash (or create one)
287             my %opt = 'HASH' eq ref $_[-1] ? %{pop @_} : ();
288              
289             # force the HDU to match a table
290             $opt{hdutype} = 'image';
291              
292             # read only one HDU
293             delete $opt{slurp};
294              
295             # attach our new options hash
296             push @_, \%opt;
297              
298             # do the whole shebang; pretend we were never here.
299             goto &rdfits;
300             }
301              
302             sub match_hdutype
303             {
304             my ( $req, $actual ) = @_;
305              
306             return (BINARY_TBL == $actual || ASCII_TBL == $actual )
307             if 'table' eq $req;
308              
309             my $reqtype = $HDUType{ $req };
310              
311             return 1 if ANY_HDU == $reqtype;
312              
313             return 1 if $reqtype == $actual;
314              
315              
316             0;
317             }
318              
319              
320             1;