File Coverage

blib/lib/PDL/IO/IDL.pm
Criterion Covered Total %
statement 233 291 80.0
branch 58 116 50.0
condition 17 45 37.7
subroutine 22 25 88.0
pod 1 18 5.5
total 331 495 66.8


line stmt bran cond sub pod time code
1             =head1 NAME
2            
3             PDL::IO::IDL -- I/O of IDL Save Files
4            
5             =head1 DESCRIPTION
6            
7             PDL::IO::IDL allows you to read and write IDL(tm) data files.
8            
9             Currently, only reading is implemented. Scalars, arrays,
10             and structures are all supported. Heap pointers, compiled code, and
11             objects are not supported. Of those three, only heap pointers are
12             likely to be supported in the future.
13            
14             This code was not developed by RSI, makers of IDL.
15            
16             =head1 NOTES
17            
18             These things seem to work:
19            
20             =over 3
21            
22             =item BYTE, SHORT, LONG, FLOAT, and DOUBLE numeric types and arrays
23            
24             All of these types seem to work fine. The corresponding variable is
25             stored as a PDL in the hash element with the same name as the original
26             variable in the file. Arrays are byteswapped as needed and are read in so
27             that the dim list has the same indexing order within PDL as it did within IDL.
28            
29             =item STRINGs and arrays of STRINGs
30            
31             String types are stored as Perl list refs, in the hash element with
32             the same name as the original variable in the file.
33            
34             =item Structures
35            
36             Structures are stored as hash refs. The elements of the hash may be
37             accessed as values within the hash.
38            
39             =item Common blocks
40            
41             Variables that are notated as being in a common block are read as
42             normal. Common-block names are collected in the special hash value
43             '+common', which contains a hash each keyword of which is the name of
44             a common block and each value of which is an array of variable names.
45            
46             =back
47            
48             These things are known to be not working and may one day be fixed:
49            
50             =over 3
51            
52             =item COMPLEX numbers
53            
54             These could be implemented as 2-arrays or as PDL::Complex values, but aren't yet.
55            
56             =item PTR types
57            
58             These could be implemented as perl refs but currently aren't.
59            
60             =item writing
61            
62             Maybe one day -- but why bother writing a broken file format? NetCDF is better.
63            
64             =back
65            
66             These things are known to be not working and will probably never be fixed
67            
68             =over 3
69            
70             =item Compiled code
71            
72             Decompiling IDL code is a violation of the IDL end-user license. To
73             implement this, someone who does not hold an IDL license would have to
74             reverse-engineer a set of .SAV files sent to that person by someone
75             else with an IDL license.
76            
77             =item Objects
78            
79             IDL objects contain compiled code.
80            
81             =back
82            
83             =head1 FUNCTIONS
84            
85             =cut
86            
87             package PDL::IO::IDL;
88            
89 1     1   77055 use strict;
  1         2  
  1         48  
90 1     1   7 use warnings;
  1         1  
  1         42  
91 1     1   4 use Exporter ();
  1         2  
  1         80  
92             package PDL::IO::IDL;
93             our @ISA = qw( Exporter );
94             our @EXPORT_OK = qw( ridl );
95             our @EXPORT = @EXPORT_OK;
96             our @EXPORT_TAGS = ( Func=>[@EXPORT_OK] );
97            
98             our $VERSION = "2.098";
99             $VERSION = eval $VERSION;
100            
101 1     1   500 use PDL;
  1         240  
  1         5  
102 1     1   179353 use PDL::Exporter;
  1         3  
  1         4  
103 1     1   30 use Carp;
  1         2  
  1         64  
104            
105 1     1   6 use PDL::Types;
  1         3  
  1         5478  
106            
107             =head2 ridl
108            
109             =for usage
110            
111             $x = ridl("foo.sav");
112            
113             =for ref
114            
115             Read an IDL save file from a file.
116            
117             Upon successful completion, $x is a hash ref containing all of the
118             variables that are present in the save file, indexed by original
119             variable name.
120            
121             IDL identifiers are case insensitive; they're all converted to
122             upper-case in the hash that gets returned. This may be adjustable at
123             a future date. Furthermore, because IDL identifiers can't contain
124             special characters, some fields that start with '+' are used to store
125             metadata about the file itself.
126            
127             Numeric arrays are stored as PDLs, structures are stored as hashes,
128             and string and structure arrays are stored as perl lists. Named
129             structure types don't exist in perl in the same way that they do in
130             IDL, so named structures are described in the 'structs' field of the
131             global metadata. Anonymous structures are treated as simple hashes.
132             Named structures are also simple hashes, but they also contain a field
133             '+name' that refers to the name of the structure type.
134            
135             =cut
136            
137            
138             sub ridl {
139 1     1 1 291701 my( $name ) = shift;
140            
141 1         21 STDERR->autoflush(1);
142            
143 1 50       124 open(IDLSAV,"<$name") || barf("ridl: Can't open `$name' for reading\n");
144            
145 1         7 my $hash = read_preamble();
146            
147 1         5 read_records($hash);
148            
149 1         3 my @snames = sort keys %{$PDL::IO::IDL::struct_table};
  1         7  
150 1         8 @snames = grep(!m/^\+/,@snames);
151 1 50       4 if(@snames) {
152 0         0 $hash->{'+structs'}={};
153 0         0 local $_;
154 0         0 for(@snames) {
155             $hash->{'+structs'}->{$_} =
156 0         0 $PDL::IO::IDL::struct_table->{$_}->{'names'};
157             }
158             }
159            
160 1         7 return $hash;
161             }
162            
163            
164             ############################################################
165             ##
166             ## Data structure definitions...
167             ##
168             ## This is a list, each element of which contains a description and
169             ## subroutine to read that particular record type.
170             ##
171            
172             our $types = [ ['START_MARKER',undef] # 0 (start of SAVE file)
173             ,['COMMON_BLOCK',\&r_com] # 1 (COMMON block definition)
174             ,['VARIABLE',\&r_var] # 2 (Variable data)
175             ,['SYSTEM_VARIABLE',undef] # 3 (System variable data)
176             ,undef # 4 (??)
177             ,undef # 5 (??)
178             ,['END_MARKER',\&r_end] # 6 (End of SAVE file)
179             ,undef # 7 (??)
180             ,undef # 8 (??)
181             ,undef # 9 (??)
182             ,['TIMESTAMP',\&r_ts] # 10 (Timestamp of the save file)
183             ,undef # 11 (??)
184             ,['COMPILED',undef] # 12 (Compiled procedure or func)
185             ,['IDENTIFICATION',undef] # 13 (Author identification)
186             ,['VERSION',\&r_v] # 14 (IDL Version information)
187             ,['HEAP_HEADER',undef] # 15 (Heap index information)
188             ,['HEAP_DATA',undef] # 16 (Heap data)
189             ,['PROMOTE64',\&r_p64] # 17 (Starts 64-bit file offsets)
190             ];
191            
192            
193             ############################################################
194             ##
195             ## Vtypes -- Representations of IDL scalar variable types.
196             ## The first element is the name, the second element is either a
197             ## perl string (that should be fed to unpack) or a code ref to a
198             ## sub that decodes the type.
199             ##
200            
201             our $vtypes = [
202             undef # 0
203             ,["Byte", \&r_byte_pdl, [] ] # 1
204             ,["Short", \&r_n_cast, [long,short] ] # 2
205             ,["Long", \&r_n_pdl, [long] ] # 3
206             ,["Float", \&r_n_pdl, [float] ] # 4
207             ,["Double", \&r_n_pdl, [double] ] # 5
208             ,["Complex", undef ] # 6
209             ,["String", \&r_strvar, [] ] # 7
210             ,["Structure", sub {}, [] ] # 8
211             ,["ComplexDbl",undef ] # 9
212             ,["HeapPtr", undef ] # 10
213             ,["Object", undef ] # 11
214             ,["UShort", \&r_n_cast, [long,ushort] ] # 12
215             ,["ULong", \&r_n_pdl, [long] ] # 13
216             ,["LongLong", undef ] # 14
217             ,["ULongLong", undef ] # 15
218             ];
219            
220            
221             ###
222             # Cheesy way to check if 64-bit is OK
223             our $quad_ok = eval { my @a = unpack "q","00000001"; $a[0]; };
224            
225             ### Initialized in read_preamble.
226             our $little_endian;
227             our $swab;
228             our $p64;
229            
230            
231             ##############################
232             #
233             # read_preamble
234             #
235             # Reads the preamble of a file and returns the preamble as a hash
236             # ref. In case of failure, it barfs. Also initializes the structure table.
237             #
238            
239             sub read_preamble {
240 1     1 0 3 my $buf;
241             my $out;
242            
243 1 50       97 sysread(IDLSAV,$buf,4) || barf ("PDL::IO::IDL: Couldn't read preamble\n");
244 1         9 my @sig = unpack("a2S",$buf);
245            
246 1 50       5 barf("PDL::IO::IDL: This isn't an IDL save file (wrong magic)\n")
247             if($sig[0] ne 'SR');
248            
249 1 50 33     7 if($sig[1] == 1024 || $sig[1] == 4) {
250 1         9 $little_endian = ($sig[1] == 1024);
251             } else {
252 0         0 barf "Unrecognized IDL save file type\n";
253             }
254            
255 1         3 $swab = $little_endian;
256            
257 1         2 $p64 = 0;
258            
259 1         3 $PDL::IO::IDL::struct_table = {};
260            
261 1         5 return {"+meta"=>{}};
262             }
263            
264             ##############################
265             #
266             # read_records
267             #
268             # Reads all the records of the file. Splits out into several other
269             # types of record reader...
270             #
271             #
272            
273             sub read_records {
274 1     1 0 2 my $hash = shift;
275 1         5 my ($buf, $tbuf);
276            
277 1         0 my $retval;
278            
279 1         0 my %nexts;
280 1         3 my $tag_count = 0;
281 1         2 do {
282            
283             ### Read header of the record
284            
285 9 50       75 sysread(IDLSAV, $tbuf, 4) || barf("PDL::IO::IDL: unexpected EOF\n");
286 9         28 my $type = unpack "N",$tbuf;
287            
288             ### Record the next seek location
289             ### (and discard 8 more bytes)
290            
291 9         13 my $next;
292 9 50       24 if($p64) {
293 0 0       0 print "Reading 64-bit location..." if($PDL::debug);
294 0         0 sysread(IDLSAV,$buf,8 + 8);
295 0         0 my @next = unpack "NN",$buf;
296 0         0 $next = $next[1] + 2**32 * $next[0];
297             } else {
298 9 50       21 print "Reading 32-bit location..." if($PDL::debug);
299 9         44 sysread(IDLSAV,$buf,4 + 8);
300 9         20 $next = unpack "N",$buf;
301             }
302 9 50       25 print "$next\n" if($PDL::debug);
303            
304             ###
305             ### Infinite-loop detector
306             ###
307            
308             barf("Repeat index finder was activated! This is a bug or a problem with your file.\n")
309 9 50       28 if($nexts{$next}) ;
310 9         25 $nexts{$next} = 1;
311            
312             ###
313             ### Call the appropriate handling routine
314             ###
315            
316 9         17 $retval = 1;
317            
318 9 100       28 if(defined $types->[$type]) {
319 8 50       19 if(defined ($types->[$type]->[1])) {
320 8 50 33     35 print "Found record of type $types->[$type]->[0]...\n" if($PDL::debug || $PDL::IO::IDL::test);
321 8         14 $retval = &{$types->[$type]->[1]}($hash);
  8         28  
322 8 50       26 print "OK.\n" if($PDL::debug);
323             } else {
324 0         0 print STDERR "Ignoring record of type ".$types->[$type]->[0]." - not implemented.\n";
325             }
326             } else {
327 1         32 print STDERR "\nIgnoring record of unknown type $type - not implemented.\n";
328             }
329 9 50 33     41 print "Seeking $next ($tag_count tags read so far...)\n" if($PDL::debug || $PDL::IO::IDL::test);
330 9         16 $tag_count++;
331 9         51 sysseek(IDLSAV, $next, 0);
332 9         34 $FOO::hash = $hash;
333             } while($retval);
334            
335             }
336            
337            
338            
339            
340             ##############################
341             # r_com
342             #
343             # Jumptable entry for the COMMONBLOCK keyword -- this loads
344             # the variable names that belong in the COMMON block into a
345             # metavariable.
346            
347             sub r_com {
348 0     0 0 0 my $hash = shift;
349 0         0 my $buf;
350            
351 0         0 sysread(IDLSAV,$buf,4);
352 0         0 my $nvars = unpack "N",$buf;
353            
354 0         0 my $name = r_string();
355 0         0 $hash->{"+common"}->{$name} = [];
356            
357 0         0 for my $i(1..$nvars) {
358 0         0 push(@{$hash->{"+common"}->{$name}},r_string());
  0         0  
359             }
360            
361 0         0 return 1;
362             }
363            
364            
365            
366            
367             ##############################
368             # r_end
369             #
370             # Jumptable entry for the END TABLE keyword -- just return 0.
371            
372 1     1 0 4 sub r_end { 0; }
373            
374            
375             ##############################
376             # r_ts
377             #
378             # TIMESTAMP record handler
379             #
380             sub r_ts {
381 1     1 0 2 my $hash = shift;
382 1         2 my $buf;
383            
384             ### Read and discard a LONARR(258) -- why? I don't know.
385 1         8 sysread(IDLSAV,$buf,1024);
386 1         7 $hash->{"+meta"}->{t_date} = r_string();
387 1         3 $hash->{"+meta"}->{t_user} = r_string();
388 1         4 $hash->{"+meta"}->{t_host} = r_string();
389            
390 1         22 return 1;
391             }
392            
393            
394            
395             ##############################
396             # r_version
397             #
398             # VERSION record handler
399             #
400             sub r_v {
401 1     1 0 2 my $hash = shift;
402 1         3 my $buf;
403             my $version;
404            
405 1         7 sysread(IDLSAV,$buf,4);
406 1         5 $version = $hash->{"+meta"}->{v_fmt} = unpack "N",$buf;
407            
408             # barf("Unknown IDL save file version ".$version)
409 1 50 33     51 print STDERR "Warning: IDL file is v$version (neither 5 nor 6); winging it. Check results!\n"
410             if($version != 5 && $version != 6);
411            
412 1         4 $hash->{"+meta"}->{v_arch} = r_string();
413 1         4 $hash->{"+meta"}->{v_os} = r_string();
414 1         19 $hash->{"+meta"}->{v_release} = r_string();
415 1         2 return 1;
416             }
417            
418             ##############################
419             # r_p64
420             sub r_p64 {
421 0     0 0 0 my $hash = shift;
422 0         0 $p64 = 1;
423             }
424            
425             ##############################
426             # r_var
427             #
428             # VARIABLE reader - parse a single variable out of a VARIABLE record.
429             #
430            
431             sub r_var {
432 5     5 0 9 my $hash = shift;
433            
434             ### Read in the variable name
435 5         13 my $name = r_string();
436            
437            
438             ### Read in and parse the type
439            
440 5         8 my $buf;
441 5         25 sysread(IDLSAV,$buf,8);
442 5         16 my ($type,$flags) = unpack "NN",$buf;
443            
444 5 50       19 unless(defined $vtypes->[$type]) {
445 0         0 barf("PDL::IO::IDL: Unknown variable type $type");
446             }
447            
448 5 50       13 unless(defined $vtypes->[$type]->[1]) {
449 0         0 print STDERR "Ignoring variable $name: unsupported type ".$vtypes->[$type]->[0]."\n";
450 0         0 return 1;
451             }
452            
453 5 50       12 print "Variable $name found (flags is $flags)...\n" if($PDL::debug);
454            
455 5 100 66     30 if((($flags & 4) == 0) and (($flags & 32) == 0)) {
456 3 50       7 print "it's a scalar\n" if($PDL::debug);
457            
458            
459 3         16 sysread(IDLSAV,$buf,4);
460 3         7 my($seven) = unpack "N",$buf;
461 3 50       11 if($seven != 7) {
462 0         0 print STDERR "Warning: expected data-start key (7) but got $seven, for variable $name\n";
463             }
464            
465             ## Scalar case
466             $hash->{$name} =
467 3         11 &{$vtypes->[$type]->[1]}
468 3         7 ($flags, [], @{$vtypes->[$type]->[2]})
  3         54  
469             } else {
470             ## Array case
471            
472 2         6 my($arrdesc) = r_arraydesc();
473            
474 2 100       12 if(($flags & 32) == 0) {
475            
476             ## Simple array case
477 1         13 sysread(IDLSAV,$buf,4);
478 1         4 my($indicator) = unpack "N",$buf;
479            
480 1 50       4 print STDERR "Warning: Reading data from an array but got code $indicator (expected 7)\n"
481             if($indicator != 7);
482            
483 1 50       4 print "simple array...type=$type\n" if($PDL::debug);
484            
485 1         3 my @args= ($flags,[ @{$arrdesc->{dims}}[0..$arrdesc->{ndims}-1]],
486 1         6 @{$vtypes->[$type]->[2]});
  1         5  
487 1         2 my $pdl = &{$vtypes->[$type]->[1]}(@args);
  1         4  
488 1         10 $hash->{$name} = $pdl;
489            
490             } else {
491            
492             ## Structure case
493 1 50       4 print "structure...\n" if($PDL::debug);
494 1         5 my($sname) = r_structdesc();
495            
496 1         2 my @structs;
497 1 50 33     7 print "Reading $arrdesc->{nelem} structures....\n" if($PDL::debug || $PDL::IO::IDL::test);
498 1         2 my $i;
499            
500 1         1 {my $buf; sysread(IDLSAV,$buf,4);}
  1         2  
  1         14  
501            
502 1         51 for ($i=0;$i<$arrdesc->{nelem};$i++) {
503 1 50 33     10 if($PDL::IO::IDL::test && !($i%100)){
504 0         0 print "$i of $arrdesc->{nelem}...\n";
505             }
506            
507 1         5 push(@structs,r_struct($sname));
508             }
509            
510             # Make a multi-dimensional list that contains the structs
511 1         6 $hash->{$name} = multi_dimify($arrdesc,\@structs,0);
512            
513             }
514             }
515            
516            
517 5         50 return 1;
518             }
519            
520            
521             ##############################
522             # multi_dimify
523             #
524             # Take a linear list of items and an array descriptor, and
525             # hand back a multi-dimensional perl list with the correct dimension
526             # according to the descriptor. (This isn't necessary for PDL types,
527             # only for structures and strings).
528             #
529            
530             sub multi_dimify {
531            
532 1     1 0 4 my($arrdesc,$structs,$n) = @_;
533            
534 1         11 return shift @{$structs}
535             if($arrdesc->{ndims} <= $n or
536             $arrdesc->{ndims} == 0 or
537 1 50 33     19 $arrdesc->{ndims}-$n == 1 && $arrdesc->{dims}->[$n]==1);
      33        
      33        
538            
539            
540 0 0       0 if($arrdesc->{ndims} - $n == 1){
541 0         0 my @ret = splice @{$structs},0,$arrdesc->{dims}->[$n];
  0         0  
542 0         0 return \@ret;
543             }
544            
545            
546 0         0 my $out = [];
547 0         0 my $i;
548 0         0 for ($i=0;$i<$arrdesc->{dims}->[$n];$i++) {
549 0         0 push(@{$out},multi_dimify($arrdesc,$structs,$n+1));
  0         0  
550             }
551            
552 0         0 return $out;
553             }
554            
555            
556            
557             ######################################################################
558             ######################################################################
559            
560            
561             #
562             # r_arraydesc - read an array descriptor from the file
563             #
564            
565             our $r_arraydesc_table = ['a','b','nbytes','nelem','ndims','c','d','nmax'];
566            
567             sub r_arraydesc {
568 11     11 0 41 my $out = {};
569 11         21 my $buf;
570            
571 11         118 sysread(IDLSAV,$buf,4*8);
572            
573 11         45 my(@vals) = unpack("N"x8,$buf);
574 11 50       33 print STDERR "r_arraydesc_table: vals[0]=".$vals[0]." (should be 8)\n"
575             if($vals[0] != 8);
576 11         29 for my $i(0..7) {
577 88         275 $out->{$r_arraydesc_table->[$i]} = $vals[$i];
578             }
579 11         22 my $nmax = $vals[7];
580 11         20 my $nelem = $vals[3];
581            
582 11         75 sysread(IDLSAV,$buf,$nmax*4);
583 11         72 $out->{dims} = [unpack("N"x$nmax,$buf)];
584 11         23 my $dims = pdl(@{$out->{dims}});
  11         42  
585            
586 11         777 $out->{pdldims} = $dims;
587            
588 11 50       43 print STDERR "PDL::IO::IDL: Inconsistent array dimensions in variable (nelem=$nelem, dims=".join("x",@{$out->{dims}}).")"
  0         0  
589             if($nelem != $dims->prod);
590            
591 11         2979 $out;
592             }
593            
594            
595             ##############################
596             #
597             # r_structdesc reads a structure description and stores it in the struct_table.
598             # You get back the name of the structure.
599             #
600            
601             sub r_structdesc {
602 1     1 0 2 my $buf;
603            
604 1 50       4 print "Reading a structure description...\n" if($PDL::IO::IDL::test);
605            
606 1         39 sysread(IDLSAV,$buf,4); # Discard initial long (value=9) from descriptor
607 1         7 my($name) = r_string(); # Have to store structures in the structure table.
608 1         4 $name =~ s/\s//g;
609            
610 1 50       6 $name = "+anon".scalar(keys %{$PDL::IO::IDL::struct_table})
  1         6  
611             if($name eq '');
612            
613 1         6 sysread(IDLSAV,$buf,4*3);
614 1         5 my($predef,$ntags,$nbytes) = unpack("N"x3,$buf);
615 1 50       4 print "predef=$predef,ntags=$ntags,nbytes=$nbytes\n" if($PDL::debug);
616 1 50       5 if(!($predef & 1)) {
617 1         2 my $i;
618 1 50 33     44 print "not predefined. ntags=$ntags..\n" if($PDL::debug || $PDL::IO::IDL::test);
619            
620 1         11 my $st = $PDL::IO::IDL::struct_table->{$name} = {
621             "ntags" => $ntags
622             ,"nbytes"=> $nbytes
623             ,"names" => []
624             ,"arrays" => []
625             ,"structs" => []
626             };
627            
628             ### Read tag descriptors.
629 1         11 sysread(IDLSAV,$buf,3*4*$ntags);
630 1         14 $st->{descrip} = [(unpack "N"x(3*$ntags), $buf)];
631            
632            
633 1 50 33     10 print "ntags is $ntags\n" if($PDL::debug || $PDL::IO::IDL::test);
634             ### Read tag names.
635 1         5 for $i(0..$ntags-1) {
636 19         28 push(@{$st->{names}},r_string());
  19         39  
637             }
638            
639             ### Search for nested arrays & structures
640 1         3 my ($nstructs,$narrays) = (0,0);
641            
642 1         4 for $i(0..$ntags-1) {
643 19         34 my $x = $st->{descrip}->[$i*3+2];
644            
645 19 50       47 $nstructs++ if($x & 32);
646 19 100       61 $narrays++ if($x & 38);
647             }
648            
649 1 50 33     10 print "narrays=$narrays\n" if($PDL::debug || $PDL::IO::IDL::test);
650 1         4 for $i(0..($narrays-1)) {
651 9         16 push( @{$st->{arrays}}, r_arraydesc() );
  9         39  
652             }
653            
654 1 50 33     8 print "nstructs=$nstructs\n" if($PDL::debug || $PDL::IO::IDL::test);
655 1         6 for $i(0..($nstructs-1)) {
656 0         0 push( @{$st->{structs}}, r_structdesc() );
  0         0  
657             }
658            
659             }
660 1 50       5 print "finished with structure desc...\n" if($PDL::IO::IDL::test);
661 1         4 return $name;
662             }
663            
664             ##############################
665             #
666             # r_struct
667             #
668             # Given the name of a structure type, read in exactly one of them.
669             # If I were smarter, this would be the same code as the variable
670             # reader, but I'm not so it's only similar.
671             #
672             our $r_struct_recursion = 0;
673            
674             sub r_struct {
675 1     1 0 3 my($sname) = shift;
676            
677            
678 1 50       4 print +("_ "x$r_struct_recursion) . "Reading a structure...\n" if($PDL::IO::IDL::test);
679 1         3 my $zz=$r_struct_recursion;
680 1         2 local($r_struct_recursion) = $zz++;
681            
682             # Get the structure descriptor from the table.
683 1         5 my($sd) = $PDL::IO::IDL::struct_table->{$sname};
684 1 50       3 barf "Unknown structure type $sname" unless defined($sd);
685            
686             # Initialize the structure itself and the array and structure indices.
687 1         3 my($struct) = {};
688 1 50       6 $struct->{'+name'} = $sname unless($sname =~ m/^\+/);
689            
690 1         4 my($array_no, $struct_no);
691            
692             # Loop over tags and snarf each one
693 1         0 my($i);
694 1         4 for($i=0;$i<$sd->{ntags};$i++) {
695 19         59 my($name) = $sd->{names}->[$i];
696            
697 19         48 my($type) = $sd->{descrip}->[$i*3+1];
698 19         45 my($flags) = $sd->{descrip}->[$i*3+2];
699            
700 19 50       44 print "reading tag #$i ($sd->{names}->[$i])\n" if($PDL::debug);
701            
702 19 50       48 barf("PDL::IO::IDL: Unknown variable type $type in structure")
703             unless defined($vtypes->[$type]);
704            
705 19 50       45 unless(defined($vtypes->[$type]->[1])) {
706 0         0 print "Skipping tag $name in structure - unsupported type ".$vtypes->[$type]->[0]."\n";
707 0 0       0 $array_no++ if($flags & 38);
708 0 0       0 $struct_no++ if($flags & 32);
709            
710             } else {
711            
712 19 100 66     75 if( (($flags & 4)==0) and (($flags & 32)==0) ) {
713             ## Scalar tag case
714 10         48 $struct->{$name} = &{$vtypes->[$type]->[1]}
715 10         20 ($flags, [], @{$vtypes->[$type]->[2]});
  10         25  
716             } else {
717            
718             ### Array and/or structure case ###
719            
720 9         21 my($arrdesc) = $sd->{arrays}->[$array_no++];
721             # sysread(IDLSAV,my $buf,4); # skip indicator
722            
723 9 50       20 if(($flags & 32) == 0) {
724            
725             ### Tag is a simple array ###
726            
727 9         24 my @args = ($flags,[ @{$arrdesc->{dims}}[0..$arrdesc->{ndims}-1]],
728 9         29 @{$vtypes->[$type]->[2]});
  9         26  
729 9         16 my $pdl = &{$vtypes->[$type]->[1]}(@args);
  9         21  
730 9 50       93 print " pdl is $pdl\n" if($PDL::debug);
731 9         55 $struct->{$name} = $pdl;
732            
733             } else {
734            
735             ### Tag is a structure ###
736            
737 0         0 my $tsname = $sd->{structs}->[$struct_no++];
738 0         0 my @structs = ();
739 0         0 for $i(1..$arrdesc->{nelem}) {
740 0         0 push(@structs,r_struct($tsname));
741             }
742            
743 0         0 $struct->{$name} = multi_dimify($arrdesc,\@structs,0);
744            
745             }
746             }
747             }
748             } # end of ntags loop
749            
750 1         49 return $struct;
751             }
752            
753            
754            
755            
756             ##############################
757             #
758             # r_string
759             #
760             # Reads a string value, leaving the file pointer correctly aligned
761             # on a 32-bit boundary (if it started that way). Returns the string as
762             # a perl scalar.
763             #
764             sub r_string{
765 33     33 0 57 my ($buf,$foo);
766 33         169 sysread(IDLSAV, $buf, 4); # Read the length...
767            
768 33         76 my ($len) = unpack "N",$buf;
769             # Pad the length out to the next 32-bit boundary
770            
771 33         57 my $plen = $len - ($len % -4) ;
772            
773 33         133 sysread(IDLSAV,$buf,$plen);
774 33         142 return unpack "A$len",$buf;
775             }
776            
777            
778             ##############################
779             #
780             # r_strvar
781             #
782             # Reads a string variable (different than r_string because
783             # of the extra length duplication in the IDL file...)
784             #
785             sub r_strvar {
786 2     2 0 6 my $buf;
787 2         4 my $flags = shift;
788 2         19 sysread(IDLSAV,$buf,4);
789 2         7 return r_string();
790             }
791            
792             ##############################
793             #
794             # r_byte_pdl
795             #
796             # Reads a byte PDL (stored as a strvar)
797             #
798             sub r_byte_pdl {
799 0     0 0 0 my($flags,$dims) = @_;
800            
801 0 0       0 sysread(IDLSAV,my $buf,4)
802             if($#$dims > 1);
803            
804 0         0 my $x = r_string();
805            
806 0         0 my $pdl = PDL->new;
807 0         0 $pdl->set_datatype(byte->enum);
808 0         0 $pdl->setdims($dims);
809 0         0 ${ $pdl->get_dataref() } = $x;
  0         0  
810 0         0 $pdl->upd_data;
811            
812 0         0 $pdl;
813             }
814            
815             ##############################
816             #
817             # r_n_pdl
818             #
819             # Reads normal integer-type numerical values as a pdl.
820             # You feed in the dimlist and type, you get back the
821             # final pdl. The read is padded to the nearest word boundary.
822             #
823            
824             sub r_n_pdl {
825 21     21 0 49 my($flags,$dims,$type) = @_;
826 21         100 $type = PDL::Type->new($type);
827 21         160 my $nelem = pdl($dims)->prod;
828 21         1728 my $hunksize = PDL::Core::howbig($type->enum) * $nelem;
829 21         1019 my $pdl = PDL->new_from_specification($type,@$dims);
830 21         83 my $dref = $pdl->get_dataref();
831 21         93 my $len = sysread(IDLSAV, $$dref, $hunksize - ($hunksize % -4) );
832 21         2279 $pdl->upd_data;
833 21 50       63 print "bytes were ",join(",",unpack "C"x($hunksize-($hunksize%-4)),$$dref),"\n" if($PDL::debug);
834 21 50       93 $type->bswap->($pdl) if $swab;
835 21         538 $pdl;
836             }
837            
838             sub r_n_cast {
839 3     3 0 9 my($flags,$dims,$type1,$type2) = @_;
840            
841 3         9 (r_n_pdl($flags,$dims,$type1))->convert($type2);
842             }
843            
844            
845             =head1 AUTHOR, LICENSE, NO WARRANTY
846            
847             THIS CODE IS PROVIDED WITH NO WARRANTY and may be distributed and/or
848             modified under the same terms as PDL itself.
849            
850             This code is based on the analysis of the IDL save file format
851             published by Craig Markwardt in 2002.
852            
853             IDL is a trademark of Research Systems Incorporated (RSI). The PDL
854             development team, and authors of this code, are not affiliated with RSI.
855            
856             =cut
857            
858             1;